Topic Description:
Given a tree, n nodes, each node represents a gravel heap. There are m operations, the operation of two kinds, the first one to modify the number of stones in the node, the second query two nodes on the path of all the gravel heap play Nim game, whether win.
Data range: n,m<=500000, number of gravel piles <=int_max
Analysis:
The first thing you need to know is that the Nim game's winning situation is the stone heap of the difference or not 0. Based on the following properties, it can be proved.
1. All the Stones will be defeated, and the difference is 0.
2. Any XOR or non-0 situation, there is a method, can be converted to the situation of XOR and 0.
3. The situation of arbitrary XOR and 0 is, in any case, converted into a situation of XOR or non-0.
The original problem is then converted to the stone heap xor on the path.
Method one: Using a chain profile for LCA, and using a segment tree or tree array to maintain the XOR on the heavy chain, the query can be completed in log2 (n) time.
Method Two: First do DFS processing, get a DFS sequence, each node in the sequence appears two times, into the stack once, out of the stack, in any subtree in the DFS sequence is a continuous interval.
Use a tree-like array for DFS sequences to maintain the prefix XOR.
Use multiplication to process any two-point LCA.
XOR of the query path (U,V), which is Getsum (St[u]) ^getsum (St[v]) ^stone[lca[u,v]
Where St[u] represents the position where the node U first appears in the DFS sequence.
Modify the number of stones in the node U, update (St[u],stone[u]), update (Ed[u]+1,stone[u]), update (St[u],newvalue), update (Ed[u]+1,newvalue)
The time complexity is O (MLOGN). But the constants are slightly larger. Seems to be slower than the first method.
The manual stack was written because of the fear of exploding the stack.
Method One: The chain profile for LCA, using BFS. Found a BFS can, instead of the original two times the DFS notation.
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include < algorithm>using namespace std; #define MAXN 500005int FIR[MAXN],NXT[MAXN<<1],EDGE[MAXN<<1],FA[MAXN], SON[MAXN],DEPTH[MAXN],POS[MAXN],MAXSON[MAXN],SZ[MAXN],TOP[MAXN]; #define LOWBIT (x) (x&-x) int Stone[MAXN], Xorarr[maxn];int que[maxn<<1],head,tail,ecnt;bool vis[maxn];int n,k,q;char opt[3];void getnum (int &t) {Char C t=0; int flag=1; while (C=getchar (), (c> ' 9 ' | | c< ' 0 ')) if (c== '-') flag=-1; while (c>= ' 0 ' &&c<= ' 9 ') {T=t*10+c-48;c=getchar ();} T*=flag;} void Adde (int a,int b) {ecnt++; edge[ecnt]=b,nxt[ecnt]=fir[a],fir[a]=ecnt; ecnt++; edge[ecnt]=a,nxt[ecnt]=fir[b],fir[b]=ecnt;} void insert (int id,int num) {while (id<=n) {xorarr[id]^=num; Id+=lowbit (ID); }}void BFS (int x) {que[tail++]=x; Depth[x]=1; fa[x]=0; while (head<tail) {int t=que[head++]; for (int i=fir[t];i;i=nxt[i]){int v=edge[i]; if (V!=fa[t]) {depth[v]=depth[t]+1; fa[v]=t; Que[tail++]=v; }}} for (int i=tail-1;i>=0;i--) {sz[que[i]]++; if (i==0) break; Sz[fa[que[i]]]+=sz[que[i]]; if (Sz[que[i]]>maxson[fa[que[i]]) maxson[fa[que[i]]]=sz[que[i]],son[fa[que[i]]]=que[i]; } int k=0; for (int i=0;i<tail;i++) {int t=que[i]; if (vis[t]==1) continue; top[t]=t; while (t) {vis[t]=1; xorarr[++k]=t; Insert (++k,stone[t]); Pos[t]=k; T=SON[T]; if (t) top[t]=top[fa[t]]; }}}int getsum (int id) {int sum=0; while (id>0) {Sum^=xorarr[id]; Id-=lowbit (ID); } return sum;} int query (int u,int v) {int tmp=0; while (Top[v]!=top[u]) {if (Depth[top[v]]>depth[top[u])) swap (U,V); Tmp^=getsum (pos[top[u]]-1); Tmp^=getsum (Pos[u]); U=fa[toP[u]]; } if (Depth[v]>depth[u]) swap (U,V); Tmp^=getsum (pos[v]-1); Tmp^=getsum (Pos[u]); return TMP;} void change (int u,int value) {Insert (pos[u],stone[u]); Insert (Pos[u],value); Stone[u]=value;} int main () {freopen ("nim.in", "R", stdin); Freopen ("Nim.out", "w", stdout); int A, B; Getnum (n); for (int i=1;i<=n;i++) Getnum (Stone[i]); for (int i=1;i<n;i++) Getnum (a), Getnum (b), Adde (A, a, or b); BFS (1); Getnum (q); for (int i=1;i<=q;i++) {scanf ("%s", opt); Getnum (a), getnum (b); scanf ("%d%d", &a,&b); if (opt[0]== ' C ') {change (a, b); } else if (opt[0]== ' Q ') {printf (query (b)!=0)? " Yes\n ":" no\n "); }} return 0;}
Method Two: First, the DFS sequence, multiplication and Lca,dfs adopted the non-recursive writing.
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #define MAXN 500005using namespace std; #define LOWBIT (x) (x&-x) int Fir[maxn],edge[maxn<<1],nxt[maxn<<1],ecnt,pos , N,q;char opt[3];int f[maxn][20];int depth[maxn];int que[maxn],head,tail;int btree[maxn<<1];int Stone[MAXN]; int Stk1[maxn],stk2[maxn],top,st[maxn],ed[maxn];bool vis[maxn];void getnum (int &t) {T=0;char c;int flag=1;while (c =getchar (),c< ' 0 ' | | C> ' 9 ') if (c== '-') flag=-1;while (c<= ' 9 ' &&c>= ' 0 ') {T=t*10+c-48;c=getchar ();} T*=flag;} void Adde (int a,int b) {ecnt++;edge[ecnt]=b,nxt[ecnt]=fir[a],fir[a]=ecnt;ecnt++;edge[ecnt]=a,nxt[ecnt]=fir[b],fir[ b]=ecnt;} void Dfs (int s) {stk1[++top]=s;stk2[top]=fir[s];st[s]=++pos;depth[s]=1;vis[s]=1;for (int i=0;i<19;i++) f[s][i]=0; while (top) {int i=stk2[top];if (i) {int v=edge[i];stk2[top]=nxt[i];if (!vis[v]) {vis[v]=1;depth[v]=depth[stk1[top]]+1 ; f[v][0]=stk1[top];for (int i=1;i<19;i++) F[v][i]=f[f[v][i-1]][i-1];stk1[++top]=V;ST[V]=++POS;STK2[TOP]=FIR[V];}} Elseed[stk1[top--]]=++pos;}} void Update (int x,int value) {while (x<=2*n) {btree[x]^=value;x+=lowbit (x);}} int getsum (int x) {int Sum=0;while (x>0) {sum^=btree[x];x-=lowbit (x);} return sum;} int Getlca (int a,int b) {if (Depth[a]<depth[b]) swap (A, b), int diff=depth[a]-depth[b];for (int i=0;i<20;i++) {if ( Diff>>i) &1) a=f[a][i];} if (a==b) return a;for (int i=19;i>=0;i--) {if (F[a][i]!=f[b][i]) a=f[a][i],b=f[b][i];} return f[a][0];} void change (int pos,int value) {update (St[pos],stone[pos]); update (Ed[pos],stone[pos]); update (st[pos],value); update (ed[pos],value); stone[pos]=value;} int query (int a,int b) {int sum=0;int C=getlca (a), Sum=getsum (St[a]); Sum^=getsum (St[b]); Sum^=stone[c];return sum;} in T main () {int A, getnum (n), for (int i=1;i<=n;i++) Getnum (Stone[i]), for (int i=1;i<n;i++) Getnum (a), Getnum (b), add E (A, b); DFS (1); for (int i=1;i<=n;i++) {update (st[i],stone[i]); update (Ed[i],stone[i]);} Getnum (q); for (int i=1;i<=q;i++) {scanf ("%s", opt); Getnum (a), Getnum (b), if (opt[0]== ' C ') change (a, b); else {printf (query (b)? " Yes\n ":" no\n ");}} return 0; }
bzoj2819 Nim (tree with modified query path XOR)