题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2819
题目大意:有一棵树,每个节点上有一堆石子,有两种操作:1.改变某个节点的nim值 2.问在u到v的路径上玩nim游戏是否有先手必胜策略
直接链剖即可,懂点博弈论的都知道:nim游戏中异或和为0的无先手必胜策略,否则均有先手必胜策略
这里注意几点:
1.由于点的数目巨大所以请直接上lowbit或者zkw线段树……
2.由于有可能出现链的情况所以题目里好心提示不要用dfs,然而我偏要用……
结果就是………………
3.特别注意!!!!!!!!!
代码:
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
struct Link
{
int s,t,next;
}l[2000000];
struct Point
{
int siz,dep,son,fa;
int top,num;
}p[1000000];
int d[1000000];
int w[1000000];
int g[1000000];
int c[1000000];
stack<int> S;
int n,m,tot = 0,s,t;
int lowbit(int x)
{
return (x&(-x));
}
void update(int x,int num)
{
while(x <= n)
{
d[x] ^= num;
x += lowbit(x);
}
}
int sum(int x)
{
int ans = 0;
while(x)
{
ans ^= d[x];
x -= lowbit(x);
}
return ans;
}
int sum2(int s,int t)
{
return (sum(t)^sum(s-1));
}
void dfs1(int x)
{
p[x].siz = 1;
p[x].son = 0;
w[x] = g[x];
while(w[x])
{
if(l[w[x]].t != p[x].fa)
{
p[l[w[x]].t].fa = x;
p[l[w[x]].t].dep = p[x].dep + 1;
dfs1(l[w[x]].t);
if(p[l[w[x]].t].siz > p[p[x].son].siz)
p[x].son = l[w[x]].t;
p[x].siz += p[l[w[x]].t].siz;
}
w[x] = l[w[x]].next;
}
}
void dfs2(int x)
{
p[x].top = S.top();
p[x].num = ++tot;
if(!p[x].son)
return ;
dfs2(p[x].son);
w[x] = g[x];
while(w[x])
{
if(l[w[x]].t != p[x].fa && l[w[x]].t != p[x].son)
{
S.push(l[w[x]].t);
dfs2(l[w[x]].t);
S.pop();
}
w[x] = l[w[x]].next;
}
}
void cut_tree()
{
tot = 0;
p[1].dep = 1;
dfs1(1);
tot = 0;
p[1].fa = 1;
S.push(1);
dfs2(1);
S.pop();
for(int i = 1;i <= n;i ++)
update(p[i].num,c[i]);
}
int treesum(int x,int y)
{
if(p[x].top == p[y].top)
{
if(p[x].num > p[y].num)
swap(x,y);
return sum2(p[x].num,p[y].num);
}
if(p[p[x].top].dep < p[p[y].top].dep)
swap(x,y);
int ans1 = sum2(p[p[x].top].num,p[x].num);
int ans2 = treesum(p[p[x].top].fa,y);
return (ans1^ans2);
}
void Add_Link(int s,int t)
{
l[++tot].s = s;
l[tot].t = t;
l[tot].next = g[s];
g[s] = tot;
}
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
scanf("%d",&c[i]);
for(int i = 1;i < n;i ++)
{
scanf("%d%d",&s,&t);
Add_Link(s,t);
Add_Link(t,s);
}
cut_tree();
scanf("%d",&m);
for(int i = 1;i <= m;i ++)
{
char ch[3];
scanf("%s%d%d",ch,&s,&t);
if(ch[0] == 'Q')
{
if(treesum(s,t) == 0)
printf("No\n");
else
printf("Yes\n");
}
else
{
int k = p[s].num;
update(k,sum2(k,k));
update(k,t);
}
}
return 0;
}