P3313 [SDOI2014] 旅行
P3313 [SDOI2014] 旅行
题意简述:
给一颗树,点有点权以及颜色,要求实现四种操作:
1.修改某点点权
2.修改某点颜色
3.求一条树上最短路(x,y)上颜色与 x,y 都相同的点的点权和,保证 x,y颜色相同
4.求一条树上最短路(x,y)上颜色与 x,y 都相同的点的点权最大值,保证 x,y颜色相同
Solution:
有些猎奇的树链剖分和动态开点线段树。
我们看完题目不难想到树链剖分,但是我们会发现颜色这一限制有些棘手,我们不妨转换一下,我们用树链剖分的思想得到一些连续的树链对应连续的下标区间。
然后我们维护一个动态开点线段树,其下标是又两个数字拼成的一个数:
对于一个连续的树上下标区间,我们在线段树上查询区间
Code:
#include<bits/stdc++.h> #define int long long const int N=1e5+5; const int inf=N*N; using namespace std; int n,m,rt; int col[N],w[N]; char c[N]; inline int Max(int x,int y) { return x > y ? x : y; } //Segment_Tree struct Segment_Tree{ int cnt; struct Tree{ int ls,rs,cnt,sum,mx; }t[N*40]; void pushup(int x) { t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum; t[x].mx = t[t[x].ls].mx > t[t[x].rs].mx ? t[t[x].ls].mx : t[t[x].rs].mx; } void insert(int &x,int l,int r,int pos,int val) { if(!x)x=++cnt; if(l==r){t[x].sum+=val;t[x].mx=t[x].sum;return;} int mid=l+r>>1; if(pos<=mid)insert(t[x].ls,l,mid,pos,val); if(mid<pos) insert(t[x].rs,mid+1,r,pos,val); pushup(x); } int query(int x,int l,int r,int L,int R) { if(L<=l&&r<=R)return t[x].sum; int mid=l+r>>1,res=0; if(L<=mid)res+=query(t[x].ls,l,mid,L,R); if(mid<R)res+=query(t[x].rs,mid+1,r,L,R); return res; } int ask(int x,int l,int r,int L,int R) { if(L<=l&&r<=R)return t[x].mx; int mid=l+r>>1,res=0; if(L<=mid) res = Max(res,ask(t[x].ls,l,mid,L,R)); if(mid<R) res = Max(res,ask(t[x].rs,mid+1,r,L,R)); return res; } }T; struct Graph{ int head[N]; struct Edge{ int to,nxt; }e[N<<1]; void add(int x,int y) { e[++head[0]]=Edge{y,head[x]}; head[x]=head[0]; } int fa[N],dep[N],dfn[N],rid[N]; int siz[N],son[N],top[N]; void dfs1(int x,int ff) { dep[x]=dep[fa[x]=ff]+1; for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa[x])continue; dfs1(y,x); siz[x] += siz[y]; son[x] = siz[son[x]] > siz[y] ? son[x] : y; } } void dfs2(int x,int tp) { dfn[x]=++dfn[0];rid[dfn[0]]=x; top[x]=tp; if(!son[x])return; dfs2(son[x],tp); for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa[x]||y==son[x])continue; dfs2(y,y); } } int chain_query(int x,int y,int k) { int res=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); res+=T.query(rt,1,inf,k*N+dfn[top[x]],k*N+dfn[x]); x=fa[top[x]]; } if(dep[x]<dep[y])swap(x,y); res+=T.query(rt,1,inf,k*N+dfn[y],k*N+dfn[x]); return res; } int chain_ask(int x,int y,int k) { int res=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); res=Max(res,T.ask(rt,1,inf,k*N+dfn[top[x]],k*N+dfn[x])); x=fa[top[x]]; } if(dep[x]<dep[y])swap(x,y); res=Max(res,T.ask(rt,1,inf,k*N+dfn[y],k*N+dfn[x])); return res; } }G; void work() { cin>>n>>m; for(int i=1;i<=n;i++)scanf("%lld%lld",&w[i],&col[i]); for(int i=1,x,y;i<n;i++) { scanf("%lld%lld",&x,&y); G.add(x,y);G.add(y,x); } G.dfs1(1,0); G.dfs2(1,1); for(int i=1;i<=n;i++) { int x=G.rid[i]; T.insert(rt,1,inf,col[x]*N+i,w[x]); } for(int i=1,x,y;i<=m;i++) { scanf("%s",c); scanf("%lld%lld",&x,&y); if(c[1]=='C') { int u=G.dfn[x]; T.insert(rt,1,inf,col[x]*N+u,-w[x]); col[x]=y; T.insert(rt,1,inf,col[x]*N+u,w[x]); } if(c[1]=='W') { int u=G.dfn[x]; T.insert(rt,1,inf,col[x]*N+u,y-w[x]); w[x]=y; } if(c[1]=='S') { int ans=G.chain_query(x,y,col[x]); printf("%lld\n",ans); } if(c[1]=='M') { int ans=G.chain_ask(x,y,col[x]); printf("%lld\n",ans); } } } #undef int int main() { //freopen("P3313_2.in","r",stdin);freopen("P3313.out","w",stdout); work(); return 0; }