n(n<=1e5)个数,第i个数为ai(0<=ai<=1e9),代表树的点权
以下n-1行读入树的双向边u和v
以下m(m<=1e5)个操作,每次操作读入op,s,t,操作分三种类型
1 s t 将树上1到s的路径的点权v都作v|t操作
2 s t 将树上1到s的路径的点权v都作v&t操作
3 s t 将树上1到s的路径的点权都取出来,每一个值当一堆石子,再加入一堆数量为t的石子
Ming先手,和对方用这些石子玩Nim游戏,问Ming是否必胜,玩完之后除了t那堆不放以外其余石子放回
标重儿子,预处理dfs序,拍到线段树上,裸的树剖操作,
按位开线段树,每一位开一个标记,|1、&0的时候更新标记,其余时候不管
根据nim游戏,将1到s的路径都作异或操作,最后再异或t,如果非0则必胜,否则必败
询问的时候,询问第i位对应的线段树对应的区间[ql,qr]内的1的数量,
若为奇数,说明异或结果为1,则加上1ll<
最后询问的结果非0则必胜,否则必败
单组数据,所以线段树那里没有init操作
其实就是很裸的树剖,只是我的线段树写法,常数好像有点大
不过这题不卡常哈,开了4s,程序2s过了
还是喜欢点权树剖,边权树剖把边权收进远端儿子,查询的时候还得减去lca的值,比较麻烦
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
struct edge
{
int to,nex;
}e[maxn*2];
struct node
{
int cs[32],cov[32];
node()
{
for(int i=30;i>=0;--i)
cs[i]=0,cov[i]=-1;
}
}tree[maxn*5];
//par[]:当前点的父亲
//dep[]:当前点的深度(以根为0)
//siz[]:当前点的子树大小(包括自己)
//son[]:当前点的重儿子(siz最大的那个儿子)
//id[]:dfs序时间戳
//arc[]:id[]的映射,如id[u]=v,则arc[v]=u
//top[]:某一条链最靠近树根的结点 即边最靠上的那个端点
//tree[]:按照dfs序建的线段树 重链映射到连续区间 轻链映射到一个点
//cnt:edge的标号;num:时间戳的标号
int par[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn];
int head[maxn],cnt,a[maxn];
int id[maxn],arc[maxn],num;
int n,m,op;
int s,t;
void add(int u,int v)
{
e[cnt].to=v;
e[cnt].nex=head[u];
head[u]=cnt++;
}
void init()
{
//memset(par,0,sizeof(par)); 由于dfs1的时候会覆盖 不需要
//memset(dep,0,sizeof(dep)); 由于后续dep[v]=dep[u]+1 只需更新根节点
//memset(siz,0,sizeof(siz)) 由于siz[u]=1覆盖 不需要
//memset(tree,0,sizeof(tree));
//memset(top,0,sizeof(top)); 后续都是根据根节点更新的
//memset(id,0,sizeof(id)); num=0了什么都好说
dep[1]=0;top[1]=1;
memset(son,0,sizeof(son));
memset(head,-1,sizeof(head));
cnt=num=0;
}
void dfs1(int u)
{
siz[u]=1;
for(int i=head[u];~i;i=e[i].nex)
{
int v=e[i].to;
if(v!=par[u])
{
par[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
}
void dfs2(int u)
{
id[u]=++num;//dfs序 时间戳 id[i]即在线段树的第i位 想象给一颗dfs树标号
arc[id[u]]=u;//arc[i] 第i位的值对应的原节点
if(son[u])//优先遍历重儿子 保证重链dfs序相邻
{
top[son[u]]=top[u];//重链上的根一定和父相同
dfs2(son[u]);
}
for(int i=head[u];~i;i=e[i].nex)
{
int v=e[i].to;
if(v!=par[u]&&v!=son[u])//非父 轻儿子
{
top[v]=v;//轻链以自己为根
dfs2(v);
}
}
}
void pushup(int p)
{
for(int i=30;i>=0;--i)
tree[p].cs[i]=(tree[p<<1].cs[i]+tree[p<<1|1].cs[i])%2;
}
void get_new(int p,int l,int r,int op,int v)
{
for(int i=30;i>=0;--i)
{
if(op==1&&(v>>i&1))tree[p].cs[i]=(r-l+1)%2;
if(op==2&&!(v>>i&1))tree[p].cs[i]=0;
}
}
void build(int p,int l,int r)
{
if(l==r)
{
for(int i=30;i>=0;--i)
if(a[arc[l]]>>i&1)tree[p].cs[i]=1;
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void pushdown(int i,int p,int l,int r)
{
if(~tree[p].cov[i])
{
int mid=(l+r)/2;
if(tree[p].cov[i]==1)
{
tree[p<<1].cs[i]=(mid-l+1)%2;
tree[p<<1|1].cs[i]=(r-mid)%2;
}
else
{
tree[p<<1].cs[i]=0;
tree[p<<1|1].cs[i]=0;
}
tree[p<<1].cov[i]=tree[p].cov[i];
tree[p<<1|1].cov[i]=tree[p].cov[i];
tree[p].cov[i]=-1;
}
}
void update(int p,int l,int r,int ql,int qr,int op,int v)
{
if(ql<=l&&r<=qr)
{
for(int i=30;i>=0;--i)
{
if(op==1&&(v>>i&1))
{
tree[p].cs[i]=(r-l+1)%2;
tree[p].cov[i]=1;
}
if(op==2&&!(v>>i&1))
{
tree[p].cs[i]=0;
tree[p].cov[i]=0;
}
}
return;
}
for(int i=30;i>=0;--i)
pushdown(i,p,l,r);
int mid=(l+r)>>1;
if(ql<=mid)update(p<<1,l,mid,ql,qr,op,v);
if(qr>mid)update(p<<1|1,mid+1,r,ql,qr,op,v);
pushup(p);
}
ll aski(int i,int p,int l,int r,int ql,int qr)//第i位的个数
{
if(ql<=l&&r<=qr)return tree[p].cs[i]%2;
pushdown(i,p,l,r);
ll res=0;
int mid=(l+r)>>1;
if(ql<=mid)(res+=aski(i,p<<1,l,mid,ql,qr))%2;
if(qr>mid)(res+=aski(i,p<<1|1,mid+1,r,ql,qr))%2;
return res;
}
ll ask(int p,int l,int r,int ql,int qr)//区间异或
{
ll res=0;
for(int i=30;i>=0;--i)
{
ll num=aski(i,p,l,r,ql,qr);
if(num&1)res+=(1ll<v链上的最大值 按轻重链找
{
while(top[u]!=top[v])
{
if(dep[top[u]]dep[v])update(1,1,n,id[v],id[u],op,t);
else update(1,1,n,id[u],id[v],op,t);
}
ll findxor(int u,int v)//u->v链上的最大值 按轻重链找
{
ll ans=0;
while(top[u]!=top[v])
{
if(dep[top[u]]dep[v])ans=ans^ask(1,1,n,id[v],id[u]);
else ans=ans^ask(1,1,n,id[u],id[v]);
return ans;
}
int main()
{
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);//点上有点权的情况
for(int i=1;i