题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531
题意:给出一棵树,每个节点有两个属性(x,y)。(1)改变某个节点的x属性或y属性;(2)从s到t,输出中间节点与s节点y属性相同的所有节点的x属性的和或最大值。
思路:树链剖分。之后是线段树维护。难操作的是这里有个y属性。T[y]表示y属性的根,有多少种y属性有多少个线段树。
struct node
{
i64 sum,Max;
int L,R;
};
int top[N],pos[N],b[N],cnt;
int W[N],C[N];
node a[N*40];
int e;
int T[N];
int n;
void pushUp(int t)
{
a[t].sum=a[a[t].L].sum+a[a[t].R].sum;
a[t].Max=max(a[a[t].L].Max,a[a[t].R].Max);
}
void build(int L,int R,int pos,int val,int &t)
{
if(!t) t=++e,a[t].L=a[t].R=0;
if(L==R)
{
a[t].sum=a[t].Max=val;
return;
}
int mid=(L+R)>>1;
if(pos<=mid) build(L,mid,pos,val,a[t].L);
else build(mid+1,R,pos,val,a[t].R);
pushUp(t);
}
void changeType(int x,int c)
{
if(c==C[x]) return;
int p=pos[x];
build(1,n,p,0,T[C[x]]);
C[x]=c;
build(1,n,p,W[x],T[C[x]]);
}
void changeVal(int x,int w)
{
if(w==W[x]) return;
int p=pos[x];
W[x]=w;
build(1,n,p,W[x],T[C[x]]);
}
i64 querySum(int L,int R,int ll,int rr,int t)
{
if(!t) return 0;
if(ll==L&&rr==R) return a[t].sum;
int mid=(L+R)>>1;
if(rr<=mid) return querySum(L,mid,ll,rr,a[t].L);
if(ll>mid) return querySum(mid+1,R,ll,rr,a[t].R);
return querySum(L,mid,ll,mid,a[t].L)+querySum(mid+1,R,mid+1,rr,a[t].R);
}
i64 queryMax(int L,int R,int ll,int rr,int t)
{
if(!t) return 0;
if(ll==L&&rr==R) return a[t].Max;
int mid=(L+R)>>1;
if(rr<=mid) return queryMax(L,mid,ll,rr,a[t].L);
if(ll>mid) return queryMax(mid+1,R,ll,rr,a[t].R);
i64 x=queryMax(L,mid,ll,mid,a[t].L);
i64 y=queryMax(mid+1,R,mid+1,rr,a[t].R);
return max(x,y);
}
vector<int> g[N];
int size[N];
int m;
int isOnSameChain(int x,int y)
{
return top[x]==top[y];
}
int getTop(int x)
{
return top[x];
}
int dep[N];
int f[N];
void calSum(int x,int y)
{
i64 ans=0;
int type=C[x];
while(!isOnSameChain(x,y))
{
int top1=getTop(x);
int top2=getTop(y);
if(dep[top1]<dep[top2]) swap(top1,top2),swap(x,y);
ans+=querySum(1,n,pos[top1],pos[x],T[type]);
x=f[top1];
}
if(pos[x]>pos[y]) swap(x,y);
ans+=querySum(1,n,pos[x],pos[y],T[type]);
printf("%lld\n",ans);
}
void calMax(int x,int y)
{
i64 ans=0;
int type=C[x];
while(!isOnSameChain(x,y))
{
int top1=getTop(x);
int top2=getTop(y);
if(dep[top1]<dep[top2]) swap(top1,top2),swap(x,y);
i64 tmp=queryMax(1,n,pos[top1],pos[x],T[type]);
upMax(ans,tmp);
x=f[top1];
}
if(pos[x]>pos[y]) swap(x,y);
i64 tmp=queryMax(1,n,pos[x],pos[y],T[type]);
upMax(ans,tmp);
printf("%lld\n",ans);
}
int son[N];
void DFS(int u,int pre)
{
f[u]=pre;
dep[u]=dep[pre]+1;
size[u]=1;
son[u]=0;
int i,v,Max=0,t=0;
FOR0(i,SZ(g[u]))
{
v=g[u][i];
if(v==pre) continue;
DFS(v,u);
size[u]+=size[v];
if(Max<size[v]) Max=size[v],t=v;
}
son[u]=t;
}
void DFS1(int u,int pre,int root)
{
top[u]=root;
cnt++;
pos[u]=cnt;
b[cnt]=u;
if(son[u])
{
DFS1(son[u],u,root);
int i,v;
FOR0(i,SZ(g[u]))
{
v=g[u][i];
if(v==pre||v==son[u]) continue;
DFS1(v,u,v);
}
}
}
int main()
{
RD(n,m);
int i,x,y,z;
FOR1(i,n) RD(W[i],C[i]);
FOR1(i,n-1)
{
RD(x,y);
g[x].pb(y);
g[y].pb(x);
}
DFS(1,0);
DFS1(1,0,1);
for(i=1;i<=n;i++) build(1,n,pos[i],W[i],T[C[i]]);
char op[10];
while(m--)
{
RD(op); RD(x,y);
if(op[0]=='C'&&op[1]=='C')
{
changeType(x,y);
}
else if(op[0]=='C'&&op[1]=='W')
{
changeVal(x,y);
}
else if(op[0]=='Q'&&op[1]=='S')
{
calSum(x,y);
}
else
{
calMax(x,y);
}
}
}