天天看点

[树链剖分 线段树] BZOJ 3531 [Sdoi2014]旅行

树链剖分 给每一个信仰开一棵线段树

然后就是动态开点的打码问题了

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define V G[p].v
using namespace std;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline void read(char *s){
	char c=nc(); int len=0;
	for (;!(c>='A' && c<='Z');c=nc());
	for (;c>='A' && c<='Z';s[++len]=c,c=nc()); s[++len]=0;
}

struct edge{
	int u,v;
	int next;
};

edge G[200005];
int head[100005],inum;

inline void add(int u,int v,int p){
	G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}

int size[100005],fat[100005],depth[100005];
int clk,tid[100005],top[100005];

inline void dfs(int u,int fa)
{
	fat[u]=fa; depth[u]=depth[fa]+1; size[u]=1;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
			dfs(V,u),size[u]+=size[V];
}

inline void find (int u,int fa,int z)
{
	tid[u]=++clk; top[u]=z;
	int maximum=0,son=0;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa && size[V]>maximum)
			maximum=size[son=V];
	if (son) find(son,u,z);
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa && V!=son)
			find(V,u,V);
}

int n,Q;
int w[100005],c[100005];

const int M=10000000;
int Stack[M+5],pnt;
int root[100005];
int ls[M+5],rs[M+5],sum[M+5],maxv[M+5];

inline void update(int x){
	sum[x]=sum[ls[x]]+sum[rs[x]]; 
	maxv[x]=max(maxv[ls[x]],maxv[rs[x]]);
}

inline void Init(){
	for (int i=M;i;i--) Stack[++pnt]=i;
}
inline int New(){
	return Stack[pnt--];
}
inline void Del(int x){
	if (x==0) return;
	sum[x]=maxv[x]=0;
	Stack[++pnt]=x;
}

inline int Sum(int &rt,int l,int r,int L,int R){
	if (sum[rt]==0) return 0;
	int mid=(l+r)>>1;
	if (l==r) return sum[rt];
	if (R<=mid)
		return Sum(ls[rt],l,mid,L,R);
	else if (L>mid)
		return Sum(rs[rt],mid+1,r,L,R);
	else 
		return Sum(ls[rt],l,mid,L,mid)+Sum(rs[rt],mid+1,r,mid+1,R);
}

inline int Max(int &rt,int l,int r,int L,int R){
	if (maxv[rt]==0) return 0;
	if (l==r) return maxv[rt];
	int mid=(l+r)>>1;
	if (R<=mid)
		return Max(ls[rt],l,mid,L,R);
	else if (L>mid)
		return Max(rs[rt],mid+1,r,L,R);
	else 
		return max(Max(ls[rt],l,mid,L,mid),Max(rs[rt],mid+1,r,mid+1,R));
}

inline void Change(int &rt,int l,int r,int x,int val){
	if (!rt) rt=New();
	if (l==r) {
		sum[rt]=maxv[rt]=val; if (!sum[rt]) Del(rt),rt=0; return;
	}
	int mid=(l+r)>>1;
	if (x<=mid) 
		Change(ls[rt],l,mid,x,val);
	else
		Change(rs[rt],mid+1,r,x,val);
	update(rt);
	if (!sum[rt]) 
		Del(rt),rt=0;
}

inline int Qsum(int u,int v,int c){
	int ret=0;
	for (;top[u]!=top[v];u=fat[top[u]])
	{
		if (depth[top[u]]<depth[top[v]]) swap(u,v);
		ret+=Sum(root[c],1,n,tid[top[u]],tid[u]);
	}
	if (depth[u]>depth[v]) swap(u,v);
	ret+=Sum(root[c],1,n,tid[u],tid[v]);	
	return ret;
}

inline int Qmax(int u,int v,int c){
	int ret=0;
	for (;top[u]!=top[v];u=fat[top[u]])
	{
		if (depth[top[u]]<depth[top[v]]) swap(u,v);
		ret=max(ret,Max(root[c],1,n,tid[top[u]],tid[u]));
	}
	if (depth[u]>depth[v]) swap(u,v);
	ret=max(ret,Max(root[c],1,n,tid[u],tid[v]));	
	return ret;
}

inline void CC(int u,int x){
	Change(root[c[u]],1,n,tid[u],0);
	c[u]=x;
	Change(root[c[u]],1,n,tid[u],w[u]);
}

inline void CW(int u,int x){
	w[u]=x;
	Change(root[c[u]],1,n,tid[u],w[u]);
}

int main()
{
	char order[5];
	int iu,iv,ans;
	Init();
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(Q);
	for (int i=1;i<=n;i++)
		read(w[i]),read(c[i]);
	for (int i=1;i<n;i++)
		read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);
	dfs(1,0);
	find(1,0,1);
	for (int i=1;i<=n;i++)
		Change(root[c[i]],1,n,tid[i],w[i]);
	while (Q--)
	{
		read(order); read(iu); read(iv);
		if (!strcmp(order+1,"CC"))
			CC(iu,iv);
		else if (!strcmp(order+1,"CW"))
			CW(iu,iv);
		else if (!strcmp(order+1,"QS"))
		{
			ans=Qsum(iu,iv,c[iu]);
			printf("%d\n",ans);
		}
		else if (!strcmp(order+1,"QM"))
		{
			ans=Qmax(iu,iv,c[iu]);
			printf("%d\n",ans);
		}
	}
	return 0;
}