题目大意:两个小人在树上玩Nim游戏,问有没有必胜策略。
思路:尼姆游戏:如果所有石子的异或值为0就是必败局面。异或有如下性质:x ^ y ^ z = x ^ (y ^ z),所以就可以进行树链剖分了。题目中还好心提醒有30%的点会使dfs爆栈。。第一次写不用dfs的树链剖分,扒的别人的代码,有些丑陋。
CODE:
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 500010 #define LEFT (pos << 1) #define RIGHT (pos << 1|1) using namespace std; const char yes[] = "Yes"; const char no[] = "No"; int points,asks; int src[MAX],line[MAX]; int head[MAX],total; int next[MAX << 1],aim[MAX << 1]; int q[MAX]; int deep[MAX],son[MAX],father[MAX],size[MAX]; int top[MAX],pos[MAX],cnt; int tree[MAX << 2]; char s[10]; inline void Add(int x,int y); void BFS(); void BuildTree(int l,int r,int _pos); bool Ask(int x,int y); int Ask(int l,int r,int x,int y,int pos); void Modify(int l,int r,int x,int pos,int c); int main() { cin >> points; for(int i = 1;i <= points; ++i) scanf("%d",&src[i]); for(int x,y,i = 1;i < points; ++i) { scanf("%d%d",&x,&y); Add(x,y),Add(y,x); } BFS(); for(int i = 1;i <= points; ++i) line[pos[i]] = src[i]; BuildTree(1,cnt,1); cin >> asks; for(int x,y,i = 1;i <= asks; ++i) { scanf("%s%d%d",s,&x,&y); if(s[0] == 'Q') puts(Ask(x,y) ? yes:no); else Modify(1,points,pos[x],1,y); } return 0; } inline void Add(int x,int y) { next[++total] = head[x]; aim[total] = y; head[x] = total; } void BFS() { int r = 0,h = 0; q[++r] = 1; while(r != h) { int x = q[++h]; deep[x] = deep[father[x]] + 1; size[x] = 1; for(int i = head[x];i;i = next[i]) { if(aim[i] == father[x]) continue; father[aim[i]] = x; q[++r] = aim[i]; } } for(int i = points;i; --i) { int x = q[i]; size[father[x]] += size[x]; if(size[x] > size[son[father[x]]]) son[father[x]] = x; } for(int i = 1;i <= points; ++i) { int x = q[i]; if(son[father[x]] == x) top[x] = top[father[x]]; else { top[x] = x; for(int j = x;j;j = son[j]) pos[j] = ++cnt; } } } void BuildTree(int l,int r,int _pos) { if(l == r) { tree[_pos] = line[l]; return ; } int mid = (l + r) >> 1; BuildTree(l,mid,_pos << 1); BuildTree(mid + 1,r,_pos << 1|1); tree[_pos] = tree[_pos << 1] ^ tree[_pos << 1|1]; } bool Ask(int x,int y) { int re = 0; while(top[x] != top[y]) { if(deep[top[x]] < deep[top[y]]) swap(x,y); re ^= Ask(1,points,pos[top[x]],pos[x],1); x = father[top[x]]; } if(deep[x] < deep[y]) swap(x,y); re ^= Ask(1,points,pos[y],pos[x],1); return re ? true:false; } int Ask(int l,int r,int x,int y,int pos) { if(l == x && y == r) return tree[pos]; int mid = (l + r) >> 1; if(y <= mid) return Ask(l,mid,x,y,LEFT); if(x > mid) return Ask(mid + 1,r,x,y,RIGHT); int left = Ask(l,mid,x,mid,LEFT); int right = Ask(mid + 1,r,mid + 1,y,RIGHT); return left ^ right; } void Modify(int l,int r,int x,int pos,int c) { if(l == r) { tree[pos] = c; return ; } int mid = (l + r) >> 1; if(x <= mid) Modify(l,mid,x,LEFT,c); else Modify(mid + 1,r,x,RIGHT,c); tree[pos] = tree[LEFT] ^ tree[RIGHT]; }
原文地址:http://blog.csdn.net/jiangyuze831/article/details/39636723