题目链接:HDU5274
【题意】
Dylans有一棵N个点的树。每个点有点权。树上节点标号为1∼N。
他得到了Q个询问,形式如下:
①0 x y:把第x个点的点权修改为y。
②1 x y:对于x∼y路径上的每一种点权,是否都出现偶数次?
保证每次询问的路径上最多只有一种点权的出现次数是奇数次。
1≤N,Q≤100000, 点权A[i]∈N,且都 ≤100000
【分析】其实可以和树上可以修改的第K大一样用主席树做,修改时候无论是+1还是-1都只要^1,最后统计1所在位置即可。空间有点大,LCA不能用ST,用线段树就好了。这样总的复杂度O(q*logn^2)时间刚刚好卡过。
【AC CODE】889ms
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <set> //#include <unordered_set> #include <queue> #include <stack> #include <vector> #include <string> #include <algorithm> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) const int INF = 0x3f3f3f3f, MAXN = 100000+10, MAXQ = 100000+10, MAXM = 100*MAXN; struct IN{ int k,a,b; }in[MAXQ]; int a[MAXN],n,num[MAXN+MAXQ],cnt,sot[MAXN+MAXQ],head[MAXN],e,nxt[MAXN<<1],to[MAXN<<1]; int sum[MAXM], lc[MAXM],rc[MAXM],tol; int rt[MAXN<<2]; inline void add_edge(int u, int v) { nxt[e] = head[u], to[e] = v; head[u] = e++; } inline int mhash(int v){return lower_bound(sot+1,sot+1+cnt,v)-sot;} int fa[MAXN], ft[MAXN], d[MAXN<<1],id[MAXN<<1],all; int df[MAXN<<1],st[MAXN],ed[MAXN],dcnt; bool ised[MAXN<<1]; void dfs(int u, int dep) { ft[u] = all, d[all] = dep, id[all++] = u; df[++dcnt] = a[u];st[u] = dcnt;ised[dcnt] = 0; for(int i = head[u]; ~i; i = nxt[i]) { int v = to[i]; if(v == fa[u]) continue; fa[v] = u; dfs(v,dep+1); d[all] = dep, id[all++] = u; } df[++dcnt] = a[u];ed[u] = dcnt;ised[dcnt] = 1; } int mi[MAXN<<2],minum[MAXN<<2]; inline int get_id(int x, int y){return x+y|x!=y;} void lca_bulid(int x, int y) { if(x == y) { mi[get_id(x,y)] = d[x]; minum[get_id(x,y)] = id[x]; return; } int m = (x+y)>>1; lca_bulid(x,m); lca_bulid(m+1,y); int u = get_id(x,y),l = get_id(x,m), r = get_id(m+1,y); if(mi[l] < mi[r]) mi[u] = mi[l], minum[u] = minum[l]; else mi[u] = mi[r], minum[u] = minum[r]; } int qid, tmpmi; void l_query(int x, int y, int ql, int qr) { if(ql <= x && y <= qr) { if(tmpmi > mi[get_id(x,y)]) tmpmi = mi[get_id(x,y)], qid = minum[get_id(x,y)]; return; } int m = (x+y)>>1; if(ql <= m) l_query(x,m,ql,qr); if(qr > m) l_query(m+1,y,ql,qr); } int lca_query(int x, int y) { x = ft[x], y = ft[y]; if(x > y) swap(x,y); tmpmi = INF; l_query(0,all-1,x,y); return qid; } void bulid(int &u, int x, int y, int p, int v) { sum[++tol] = sum[u]^1,lc[tol] = lc[u],rc[tol] = rc[u]; u = tol; if(x == y) return; int m = (x+y)>>1; if(p <= m) bulid(lc[u],x,m,p,v); else bulid(rc[u],m+1,y,p,v); } void init() { all = tol = dcnt = 0; fa[1] = 0; clc(rt,0); dfs(1,1); lca_bulid(0,all-1); rt[dcnt+1] = rt[0]; bulid(rt[dcnt+1],1,cnt,mhash(df[1]),1); repe(i,2,dcnt) { rt[i+dcnt] = rt[i-1+dcnt]; int v = 1; if(ised[i]) v = -1; bulid(rt[i+dcnt],1,cnt,mhash(df[i]),v); } } void t_update(int &u, int x, int y, int p, int v) { if(!u) {lc[++tol] = lc[u],rc[tol] = rc[u], sum[tol] = sum[u];u = tol;} sum[u] ^= 1; if(x == y) return; int m = (x+y)>>1; if(p <= m) t_update(lc[u],x,m,p,v); else t_update(rc[u],m+1,y,p,v); } inline int lowbit(int x){return x&-x;} void add(int x, int v) { int p = mhash(df[x]); while(x <= dcnt) { t_update(rt[x],1,cnt,p,v); x += lowbit(x); } } void update(int x, int v) { add(st[x],-1);//第一次出现点删掉原来加上新的 df[st[x]] = v; add(st[x],1); add(ed[x],1);//最后一次出现点相反 df[ed[x]] = v; add(ed[x],-1); } int tx[100],ty[100],len[2]; int query(int x, int y) { if(x == y) return x; int m = (x+y)>>1, tmp = 0; rep(i,0,len[1]) tmp ^= sum[rc[ty[i]]]; rep(i,0,len[0]) tmp ^= sum[rc[tx[i]]]; /*if(tmp > 1 || tmp < 0) while(1) puts("error");*/ if(tmp) { rep(i,0,len[1]) ty[i] = rc[ty[i]]; rep(i,0,len[0]) tx[i] = rc[tx[i]]; return query(m+1,y); } rep(i,0,len[1]) ty[i] = lc[ty[i]]; rep(i,0,len[0]) tx[i] = lc[tx[i]]; return query(x,m); } int main() { #ifdef SHY freopen("d:\\1.txt", "r", stdin); #endif int t; scanf("%d", &t); while(t--) { int q; scanf("%d %d",&n, &q); e = 0; clc(head,-1); rep(i,1,n) { int u,v; scanf("%d %d", &u, &v); add_edge(u,v); add_edge(v,u); } int cc = 0; repe(i,1,n) scanf("%d", &a[i]), num[++cc] = a[i]; rep(i,0,q) { scanf("%d %d %d", &in[i].k, &in[i].a, &in[i].b); if(!in[i].k) num[++cc] = in[i].b; } sort(num+1,num+1+cc); sot[cnt=1] = num[1]; repe(i,2,cc) if(num[i] != num[i-1]) sot[++cnt] = num[i]; init(); rep(i,0,q) { if(in[i].k) { len[0]=len[1]=0; int lca = lca_query(in[i].a,in[i].b); int ta = st[in[i].a], tb = st[in[i].b],tlca = st[lca],tflca = st[fa[lca]]; ty[len[1]++] = rt[ta+dcnt],ty[len[1]++] = rt[tb+dcnt];//静态初始值 for(int j = ta; j > 0; j -= lowbit(j)) ty[len[1]++] = rt[j]; for(int j = tb; j > 0; j -= lowbit(j)) ty[len[1]++] = rt[j]; tx[len[0]++] = rt[tlca+dcnt],tx[len[0]++] = rt[tflca?tflca+dcnt:0]; for(int j = tlca; j > 0; j -= lowbit(j)) tx[len[0]++] = rt[j]; for(int j = tflca; j > 0; j -= lowbit(j)) tx[len[0]++] = rt[j]; int tmp = 0; rep(j,0,len[1]) tmp ^= sum[ty[j]]; rep(j,0,len[0]) tmp ^= sum[tx[j]]; /*if(tmp > 1 || tmp < 0) while(1) puts("error"); */ if(!tmp) puts("-1"); else printf("%d\n", sot[query(1,cnt)]); } else update(in[i].a,in[i].b); } } return 0; }
还有一种q*logn的标程,就是由于最多只有一个奇数,则可以把路径上的所有值都异或,则最后结果不为0时答案就是这个值,等于0时可能有奇数个0,则需要在读入的时候把数据都+1,输出-1;用上dfs序加上树状数组维护根到点的异或值序列即可;
【AC CODE】312ms
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <set> //#include <unordered_set> #include <queue> #include <stack> #include <vector> #include <string> #include <algorithm> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) const int INF = 0x3f3f3f3f, MAXN = 100000+10; int head[MAXN],tol,nxt[MAXN<<1],to[MAXN<<1],a[MAXN],n; inline void add_edge(int u, int v) { nxt[tol] = head[u], to[tol] = v; head[u] = tol++; } int d[MAXN<<1],num[MAXN<<1],ft[MAXN],cnt, fa[MAXN]; int df[MAXN<<1],st[MAXN<<1],ed[MAXN<<1],all; void dfs(int u ,int dep) { d[++cnt] = dep,num[cnt] = u; ft[u] = cnt; df[++all] = a[u];st[u] = all; for(int i = head[u]; ~i; i = nxt[i]) { int v = to[i]; if(v == fa[u]) continue; fa[v] = u; dfs(v,dep+1); d[++cnt] = dep,num[cnt] = u; } df[++all] = a[u],ed[u] = all; } int mi[MAXN<<2],minum[MAXN<<2]; inline int id(int x, int y){return x+y|x!=y;} void bulid(int x, int y) { if(x == y) { mi[id(x,y)] = d[x]; minum[id(x,y)] = num[x]; return; } int m = (x+y)>>1; bulid(x,m); bulid(m+1,y); int u = id(x,y), l = id(x,m),r = id(m+1,y); if(mi[l] < mi[r]) mi[u] = mi[l], minum[u] = minum[l]; else mi[u] = mi[r], minum[u] = minum[r]; } int qid,qmi; void query(int x, int y, int ql, int qr) { if(ql <= x && y <= qr) { if(qmi > mi[id(x,y)]) qmi = mi[id(x,y)], qid = minum[id(x,y)]; return; } int m = (x+y)>>1; if(ql <= m) query(x,m,ql,qr); if(qr > m) query(m+1,y,ql,qr); } int lca_query(int x, int y) { x = ft[x], y = ft[y]; if(x > y) swap(x,y); qmi = INF; query(1,cnt,x,y); return qid; } int c[MAXN<<1]; inline int lowbit(int x){return x&-x;} void add(int x, int v) { while(x <= all) { c[x] ^= v; x += lowbit(x); } } int get_sum(int x) { int ans = 0; while(x > 0) { ans ^= c[x]; x -= lowbit(x); } return ans; } void init() { cnt = all = 0; dfs(1,0); bulid(1,cnt); clc(c,0); repe(i,1,all) add(i,df[i]); } int main() { #ifdef SHY freopen("d:\\1.txt", "r", stdin); #endif int t; scanf("%d", &t); while(t--) { tol = 0; clc(head,-1); int q; scanf("%d %d", &n, &q); rep(i,1,n) { int u,v; scanf("%d %d", &u, &v); add_edge(u,v); add_edge(v,u); } repe(i,1,n) scanf("%d", &a[i]),a[i]++; init(); while(q--) { int op,x,y; scanf("%d %d %d", &op, &x, &y); if(op) { int lca = lca_query(x,y); int ans = get_sum(st[x])^get_sum(st[y])^get_sum(st[lca])^get_sum(st[fa[lca]]); if(ans) printf("%d\n", ans-1); else puts("-1"); } else { y++; add(st[x],df[st[x]]); df[st[x]] = y; add(st[x],y); add(ed[x],df[ed[x]]); df[ed[x]] = y; add(ed[x],y); } } } return 0; }