https://www.lydsy.com/JudgeOnline/problem.php?id=3531
树剖加主席树
问一条链上某种颜色的权值和或最大值
可以对每种颜色建立一棵线段树 维护树剖之后的dfs序列 每次在对应颜色的线段树上操作 但是这样空间复杂度无法承受 而用主席树的话 树图上的每一个节点都只需新开辟一条链
这个方法同样可以简化(不用维护树剖)到查询一棵子树上某种颜色的数量 权值 最值 还可以简化(不用维护DSF序)查询一个区间内某种颜色的相关问题
#include <bits/stdc++.h>
using namespace std;
struct node1
{
int v;
int next;
};
struct node2
{
int l;
int r;
int val1;
int val2;
};
node1 edge[200010];
node2 tree[4000010];
int w[100010],c[100010],first[100010],deep[100010],fa[100010],sum[100010],son[100010],top[100010],mp1[100010],mp2[100010],root[100010];
int n,q,num,cnt;
void addedge(int u,int v)
{
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
}
void dfsI(int cur)
{
int i,v;
sum[cur]=1,son[cur]=-1;
for(i=first[cur];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(v!=fa[cur])
{
deep[v]=deep[cur]+1,fa[v]=cur;
dfsI(v);
sum[cur]+=sum[v];
if(son[cur]==-1||sum[son[cur]]<sum[v])
{
son[cur]=v;
}
}
}
}
void pushup(int cur)
{
tree[cur].val1=tree[tree[cur].l].val1+tree[tree[cur].r].val1;
tree[cur].val2=max(tree[tree[cur].l].val2,tree[tree[cur].r].val2);
}
int update(int rot,int tar,int val,int l,int r)
{
int cur,m;
cur=cnt++;
tree[cur]=tree[rot];
if(l==r)
{
tree[cur].val1+=val;
tree[cur].val2=tree[cur].val1;
return cur;
}
m=(l+r)/2;
if(tar<=m) tree[cur].l=update(tree[rot].l,tar,val,l,m);
else tree[cur].r=update(tree[rot].r,tar,val,m+1,r);
pushup(cur);
return cur;
}
void dfsII(int cur,int tp)
{
int i,v;
num++;
top[cur]=tp,mp1[cur]=num,mp2[num]=cur;
root[c[cur]]=update(root[c[cur]],num,w[cur],1,n);
if(son[cur]==-1) return;
dfsII(son[cur],tp);
for(i=first[cur];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(v!=fa[cur]&&v!=son[cur])
{
dfsII(v,v);
}
}
}
int build(int l,int r)
{
int cur,m;
cur=cnt++;
tree[cur].l=0,tree[cur].r=0,tree[cur].val1=0,tree[cur].val2=0;
if(l==r) return cur;
m=(l+r)/2;
tree[cur].l=build(l,m);
tree[cur].r=build(m+1,r);
return cur;
}
int query(int rot,int op,int pl,int pr,int l,int r)
{
int res,m;
if(pl<=l&&r<=pr)
{
if(op==1) return tree[rot].val1;
else return tree[rot].val2;
}
res=0,m=(l+r)/2;
if(pl<=m)
{
if(op==1) res+=query(tree[rot].l,op,pl,pr,l,m);
else res=max(res,query(tree[rot].l,op,pl,pr,l,m));
}
if(pr>m)
{
if(op==1) res+=query(tree[rot].r,op,pl,pr,m+1,r);
else res=max(res,query(tree[rot].r,op,pl,pr,m+1,r));
}
return res;
}
int solve(int op,int clr,int u,int v)
{
int res;
res=0;
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]]) swap(u,v);
if(op==1) res+=query(root[clr],op,mp1[top[u]],mp1[u],1,n);
else res=max(res,query(root[clr],op,mp1[top[u]],mp1[u],1,n));
u=fa[top[u]];
}
if(deep[u]<deep[v]) swap(u,v);
if(op==1) res+=query(root[clr],op,mp1[v],mp1[u],1,n);
else res=max(res,query(root[clr],op,mp1[v],mp1[u],1,n));
return res;
}
int main()
{
int i,u,v;
char op[10];
scanf("%d%d",&n,&q);
for(i=1;i<=n;i++)
{
scanf("%d%d",&w[i],&c[i]);
}
memset(first,-1,sizeof(first));
num=0;
for(i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
cnt=0;
root[0]=build(1,n);
for(i=1;i<=100000;i++) root[i]=root[0];
deep[1]=1,fa[1]=-1;
dfsI(1);
num=0;
dfsII(1,1);
while(q--)
{
scanf("%s%d%d",op,&u,&v);
if(op[1]=='C')
{
root[c[u]]=update(root[c[u]],mp1[u],-w[u],1,n);
root[v]=update(root[v],mp1[u],w[u],1,n);
c[u]=v;
}
else if(op[1]=='W')
{
root[c[u]]=update(root[c[u]],mp1[u],-w[u],1,n);
root[c[u]]=update(root[c[u]],mp1[u],v,1,n);
w[u]=v;
}
else if(op[1]=='S') printf("%d\n",solve(1,c[u],u,v));
else printf("%d\n",solve(2,c[u],u,v));
}
return 0;
}