51nod1819 :黑白树 V2(树链剖分)

传送门

题解:
NOIP之前当然要做做NOIp题啦!

这道题并不难(想),把一个点的权值定为 ( u f a u ) (u-fa_u) 乘上子树黑点个数,然后就相当于是支持查询链和,链修改,子树修改了,用了链剖分开维护奇偶的情况即可。

时间复杂度 O ( n log 2 n ) O(n \log^2 n)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
inline void W(LL x) {
	static int buf[50];
	if(!x) {putchar('0'); return;}
	if(x<0) {putchar('-'); x=-x;}
	while(x) {buf[++buf[0]]=x%10; x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+'0');
}

const int N=2e5+50;
int n,m,col[N],pos[N];
int tot_sze[N],sze[N][2][2],son[N],top[N],fa[N],dep[N],in[N],out[N],ind;
vector <int> g[N]; 

struct PT {
	int sum[N<<2],cnt[N<<2],rev[N<<2];
	inline void build(int k,int l,int r,int flag) {
		if(l==r) {
			sum[k]=(dep[pos[l]]&1)==flag;
			cnt[k]=(sum[k] && col[pos[l]]==1);
			return;
		} int mid=(l+r)>>1;
		build(k<<1,l,mid,flag);
		build(k<<1|1,mid+1,r,flag);
		sum[k]=sum[k<<1]+sum[k<<1|1];
		cnt[k]=cnt[k<<1]+cnt[k<<1|1];
	}
	inline void upt(int k) {
		cnt[k]=cnt[k<<1]+cnt[k<<1|1];
	}
	inline void opt(int k) {
		rev[k]^=1;
		cnt[k]=sum[k]-cnt[k];
	}
	inline void pushdown(int k) {
		if(rev[k]) {
			opt(k<<1); opt(k<<1|1);
			rev[k]=0;
		}
	}
	inline int ask(int k,int l,int r,int L,int R) {
		if(L<=l && r<=R) return cnt[k];
		pushdown(k); int mid=(l+r)>>1;
		if(R<=mid) return ask(k<<1,l,mid,L,R);
		else if(L>mid) return ask(k<<1|1,mid+1,r,L,R);
		else return ask(k<<1,l,mid,L,R)+ask(k<<1|1,mid+1,r,L,R);
	}
	inline void opt(int k,int l,int r,int L,int R) {
		if(L<=l && r<=R) {opt(k); return;}
		pushdown(k); int mid=(l+r)>>1;
		if(R<=mid) opt(k<<1,l,mid,L,R);
		else if(L>mid) opt(k<<1|1,mid+1,r,L,R);
		else opt(k<<1,l,mid,L,R), opt(k<<1|1,mid+1,r,L,R);
		upt(k); 
	}
	inline int opt(int l,int r) {
		int ans=ask(1,1,n,l,r);
		opt(1,1,n,l,r);
		return ans;
	}
	inline void init(int flag) {
		build(1,1,n,flag);	
	}
} pt[2];

struct ST {
	LL sum[N<<2][2],val[N<<2],rev[N<<2],tag[N<<2];
	inline void upt(int k) {
		sum[k][0]=sum[k<<1][0]+sum[k<<1|1][0];
		sum[k][1]=sum[k<<1][1]+sum[k<<1|1][1];
	}
	inline void add(int k,int v) {
		tag[k]+=v;
		sum[k][0]-=v*val[k];
		sum[k][1]+=v*val[k];
	}
	inline void opt(int k) {
		tag[k]=-tag[k];
		swap(sum[k][0],sum[k][1]);
		rev[k]^=1;
	}
	inline void pushdown(int k) {
		if(rev[k]) opt(k<<1), opt(k<<1|1), rev[k]=0;
		if(tag[k]) add(k<<1,tag[k]), add(k<<1|1,tag[k]), tag[k]=0;
	}
	inline void build(int k,int l,int r,int flag) {
		if(l==r) {
			val[k]=pos[l]-fa[pos[l]];
			sum[k][0]=val[k]*sze[pos[l]][flag][0];
			sum[k][1]=val[k]*sze[pos[l]][flag][1];
			return;
		} int mid=(l+r)>>1;
		build(k<<1,l,mid,flag);
		build(k<<1|1,mid+1,r,flag);
		val[k]=val[k<<1]+val[k<<1|1];
		upt(k);
	}
	inline void inc(int k,int l,int r,int L,int R,int v) {
		if(L<=l && r<=R) {add(k,v); return;}
		pushdown(k); int mid=(l+r)>>1;
		if(R<=mid) inc(k<<1,l,mid,L,R,v);
		else if(L>mid) inc(k<<1|1,mid+1,r,L,R,v);
		else inc(k<<1,l,mid,L,R,v), inc(k<<1|1,mid+1,r,L,R,v);
		upt(k);
	}
	inline void opt(int k,int l,int r,int L,int R) {
		if(L<=l && r<=R) {opt(k); return;}
		pushdown(k); int mid=(l+r)>>1;
		if(R<=mid) opt(k<<1,l,mid,L,R);
		else if(L>mid) opt(k<<1|1,mid+1,r,L,R);
		else opt(k<<1,l,mid,L,R), opt(k<<1|1,mid+1,r,L,R);
		upt(k);
	}
	inline LL ask(int k,int l,int r,int L,int R) {
		if(L<=l && r<=R) {return sum[k][1];}
		pushdown(k); int mid=(l+r)>>1;
		if(R<=mid) return ask(k<<1,l,mid,L,R);
		else if(L>mid) return ask(k<<1|1,mid+1,r,L,R);
		else return ask(k<<1,l,mid,L,R)+ask(k<<1|1,mid+1,r,L,R);
	}
	inline void add(int l,int r,int v) {
		inc(1,1,n,l,r,v);
	}
	inline void opt(int l,int r) {
		opt(1,1,n,l,r);
	}
	inline LL ask(int l,int r) {
		return ask(1,1,n,l,r);
	}
	inline void init(int flag) {
		build(1,1,n,flag);
	}
} st[2];

inline void dfs(int x,int f) {
	dep[x]=dep[f]+1; fa[x]=f;
	tot_sze[x]=sze[x][dep[x]&1][col[x]==1]=1;
	for(auto v:g[x]) if(v^f) {
		dfs(v,x); 
		sze[x][0][0]+=sze[v][0][0];
		sze[x][0][1]+=sze[v][0][1];
		sze[x][1][0]+=sze[v][1][0];
		sze[x][1][1]+=sze[v][1][1];
		tot_sze[x]+=tot_sze[v];
		if(tot_sze[son[x]]<tot_sze[v]) son[x]=v;
	}
}
inline void Dfs(int x,int f) {
	top[x]=f; in[x]=++ind; pos[ind]=x;
	if(son[x]) Dfs(son[x],f);
	for(auto v:g[x]) 
		if(v^fa[x] && v^son[x]) Dfs(v,v);
	out[x]=ind;
}
int main() {
	n=rd(), m=rd();
	for(int i=1;i<=n;i++) col[i]=rd();
	for(int i=1;i<n;i++) {
		int x=rd(), y=rd();
		g[x].push_back(y);
		g[y].push_back(x);
	} dfs(1,0); Dfs(1,1);
	pt[0].init(0); 
	pt[1].init(1);
	st[0].init(0); 
	st[1].init(1);
	for(int i=1;i<=m;i++) {
		int op=rd(), x=rd(), c=dep[x]&1;
		if(op==1) {
			int tot=sze[x][c^1][0]+sze[x][c^1][1];
			int cnt=pt[c^1].opt(in[x],out[x]);
			for(int u=fa[x];u;u=fa[top[u]]) {
				st[c^1].add(in[top[u]],in[u],-cnt);
				st[c^1].add(in[top[u]],in[u],tot-cnt);
			} st[c^1].opt(in[x],out[x]);
		} else if(op==2) {
			int cnt=pt[c].opt(in[x],in[x]);
			for(int u=x;u;u=fa[top[u]])
				st[c].add(in[top[u]],in[u],cnt?-1:1);
		} else {
			LL ans=0;
			for(int u=x;u;u=fa[top[u]]) 
				ans+=st[0].ask(in[top[u]],in[u])+st[1].ask(in[top[u]],in[u]);
			W(ans), putchar('\n');
		}
	}
}
发布了553 篇原创文章 · 获赞 227 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/83901623
今日推荐