Bzoj2819:Nim:树链剖分

题目链接:Nim

线段树维护异或值的沙茶题

然而dfs会爆栈所以得开手工栈(见代码)

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=500010;
int tot=0,h[maxn],ind=0,s[maxn],fa[maxn];
struct edge{int to,next;}G[maxn<<1];
int dep[maxn],Belong[maxn],pos[maxn];
int v[maxn],ans=0,n,m,fz[maxn];
struct seg{
	int l,r,v;
	seg *lc,*rc;
};
seg *root=new seg();
char str[5];

void add(int x,int y){
	G[++tot].to=y;G[tot].next=h[x];h[x]=tot;
}

void dfs1(int x){
	s[x]=1; dep[x]=dep[fa[x]]+1;
	for (int i=h[x];i;i=G[i].next){
		int v=G[i].to;
		if (v==fa[x]) continue;
		fa[v]=x; dfs1(v); s[x]+=s[v]; 
	}
}

void dfs2(int x,int L){
	pos[x]=++ind; int k=0; Belong[x]=L; fz[ind]=x;
	for (int i=h[x];i;i=G[i].next)
		if (s[G[i].to]>s[k]&&dep[G[i].to]>dep[x]) k=G[i].to;
	if (!k) return; dfs2(k,L);
	for (int i=h[x];i;i=G[i].next)
		if (dep[G[i].to]>dep[x]&&k!=G[i].to) dfs2(G[i].to,G[i].to); 
}

void push_up(seg *p){
	p->v=p->lc->v^p->rc->v;
}

void build(seg *p,int l,int r){
	p->l=l; p->r=r;
	if (l+1==r){
		p->v=v[fz[l]]; p->lc=p->rc=NULL; return;
	}else if (l+1<r){
		int mid=(l+r)>>1;
		p->lc=new seg();
		p->rc=new seg();
		if (l<mid) build(p->lc,l,mid);
		if (mid<r) build(p->rc,mid,r);
		push_up(p);
	}
}

void update(seg *p,int l,int r,int val){
	if (l<=p->l&&p->r<=r){p->v=val;return;}
	int mid=(p->l+p->r)>>1;
	if (l<mid) update(p->lc,l,r,val);
	if (mid<r) update(p->rc,l,r,val);
	push_up(p);
}

void ask(seg *p,int l,int r){
	if (l<=p->l&&p->r<=r){ans^=p->v;return;}
	int mid=(p->l+p->r)>>1;
	if (l<mid) ask(p->lc,l,r);
	if (mid<r) ask(p->rc,l,r); 
}

int query(int x,int y){
	int sum=0;
	while (Belong[x]!=Belong[y]){
		if (dep[Belong[x]]<dep[Belong[y]]) swap(x,y);
		ans=0; ask(root,pos[Belong[x]],pos[x]+1);
		sum^=ans; x=fa[Belong[x]];
	}
	if (dep[x]<dep[y]) swap(x,y);
	ans=0; ask(root,pos[y],pos[x]+1);
	sum^=ans; 
	return sum;
}

int main(){
	int __size__=30<<20;
	char *__p__=(char*)malloc(__size__)+__size__;
	__asm__("movl %0, %%esp\n"::"r"(__p__));
	scanf("%d",&n);
	for (int i=1;i<=n;++i)scanf("%d",&v[i]);
	for (int i=1;i<n;++i){
		int x,y; 
		scanf("%d%d",&x,&y);
		add(x,y); add(y,x);
	}
	dfs1(1);
	dfs2(1,1);
	build(root,1,n+1);
	scanf("%d",&m);
	for (int i=1;i<=m;++i){
		scanf("%s",str+1);
		if (str[1]=='C'){
			int x,y; scanf("%d%d",&x,&y);
			update(root,pos[x],pos[x]+1,y);
		}else if (str[1]=='Q'){
			int x,y; scanf("%d%d",&x,&y);
			int ret=query(x,y);
			if (ret) printf("Yes\n");
			else printf("No\n");
		}
	} 
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值