题目:洛谷3313、BZOJ3531。
题目大意:
给你一棵树,每个点有一个分类和一个值。
有四种操作:
1. 修改某个点的分类
2. 修改某个点的值
3. 查询两个分类相同的点的最短路上,与这两个点分类相同的所有点的值的和
4. 查询两个分类相同的点的最短路上,与这两个点分类相同的所有点的值的最大值
解题思路:
树链剖分。
给每个分类建一棵线段树维护。
内存不够怎么办?
动态开点即可。我用了指针+内存池大法。
C++ Code:
#include<bits/stdc++.h> #define N 100005 int n,q,w[N],c[N],cnt=0,head[N],son[N],dep[N],fa[N],sz[N],top[N],dfn[N],idx=0,tp=0; char opt[5]; struct node{ node *ld,*rd; int sum,max; }P[5000001],*STK[5000001]; inline node* newnode(){ node* p=STK[tp--]; p->ld=p->rd=NULL; p->sum=0;p->max=-0x3f3f3f3f; return p; } inline void delnode(node*& rt){ STK[++tp]=rt; rt=NULL; } class SegmentTree{ private: int val,id,L,R; void ADD(node*& rt,int l,int r){ if(rt==NULL)rt=newnode(); if(l==r)rt->sum=rt->max=val;else{ int mid=(l+r)>>1; if(id<=mid)ADD(rt->ld,l,mid);else ADD(rt->rd,mid+1,r); int sum=0,max=-0x3f3f3f3f; if(rt->ld!=NULL)sum=rt->ld->sum,max=rt->ld->max; if(rt->rd!=NULL){ sum+=rt->rd->sum; int x=rt->rd->max; if(max<x)max=x; } rt->sum=sum,rt->max=max; } } void DEL(node*& rt,int l,int r){ if(l==r){ val=rt->sum; delnode(rt); return; } int mid=(l+r)>>1; if(id<=mid)DEL(rt->ld,l,mid);else DEL(rt->rd,mid+1,r); int sum=0,max=-0x3f3f3f3f; if(rt->ld!=NULL)sum=rt->ld->sum,max=rt->ld->max; if(rt->rd!=NULL){ sum+=rt->rd->sum; int x=rt->rd->max; if(max<x)max=x; } rt->sum=sum,rt->max=max; } void qs(node* rt,int l,int r){ if(rt==NULL)return; if(L<=l&&r<=R){ val+=rt->sum; return; } int mid=(l+r)>>1; if(L<=mid)qs(rt->ld,l,mid); if(mid<R)qs(rt->rd,mid+1,r); } void qm(node* rt,int l,int r){ if(rt==NULL)return; if(L<=l&&r<=R){ if(val<rt->max)val=rt->max; return; } int mid=(l+r)>>1; if(L<=mid)qm(rt->ld,l,mid); if(mid<R)qm(rt->rd,mid+1,r); } public: node* rt; inline void init(){rt=newnode();} void modify(int num,int value){ val=value; id=num; ADD(rt,1,n); } int deletenode(int num){ id=num; DEL(rt,1,n); return val; } int query_sum(int x,int y){ int ans=0; for(;top[x]!=top[y];) if(dep[top[x]]>=dep[top[y]]){ L=dfn[top[x]],R=dfn[x]; val=0; qs(rt,1,n); ans+=val; x=fa[top[x]]; }else{ L=dfn[top[y]],R=dfn[y]; val=0; qs(rt,1,n); ans+=val; y=fa[top[y]]; } if(dep[x]<=dep[y]){ L=dfn[x],R=dfn[y]; val=0; qs(rt,1,n); ans+=val; }else{ L=dfn[y],R=dfn[x]; val=0; qs(rt,1,n); ans+=val; } return ans; } int query_max(int x,int y){ int ans=-0x3f3f3f3f; for(;top[x]!=top[y];) if(dep[top[x]]>=dep[top[y]]){ L=dfn[top[x]],R=dfn[x]; val=-0x3f3f3f3f; qm(rt,1,n); if(val>ans)ans=val; x=fa[top[x]]; }else{ L=dfn[top[y]],R=dfn[y]; val=-0x3f3f3f3f; qm(rt,1,n); if(val>ans)ans=val; y=fa[top[y]]; } if(dep[x]<=dep[y]){ L=dfn[x],R=dfn[y]; val=-0x3f3f3f3f; qm(rt,1,n); if(val>ans)ans=val; }else{ L=dfn[y],R=dfn[x]; val=-0x3f3f3f3f; qm(rt,1,n); if(val>ans)ans=val; } return ans; } }tree[N]; inline int readint(){ int c=getchar(),d=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar())d=(d<<3)+(d<<1)+(c^'0'); return d; } struct edge{ int to,nxt; }e[N<<1]; void dfs(int now){ son[now]=0; sz[now]=1; for(int i=head[now];i;i=e[i].nxt) if(!dep[e[i].to]){ dep[e[i].to]=dep[now]+1; fa[e[i].to]=now; dfs(e[i].to); sz[now]+=sz[e[i].to]; if(!son[now]||sz[son[now]]<sz[e[i].to])son[now]=e[i].to; } } void dfs2(int now){ dfn[now]=++idx; if(son[now])top[son[now]]=top[now],dfs2(son[now]); for(int i=head[now];i;i=e[i].nxt) if(dep[now]<dep[e[i].to]&&e[i].to-son[now])dfs2(top[e[i].to]=e[i].to); } inline void memory_init(){ for(int i=0;i<5000001;++i) STK[i]=&P[i]; tp=5000000; } int main(){ memory_init(); for(int i=1;i<N;++i)tree[i].init(); n=readint(),q=readint(); for(int i=1;i<=n;++i)w[i]=readint(),c[i]=readint(); memset(head,0,sizeof head); for(int i=1;i<n;++i){ int u=readint(),v=readint(); e[++cnt]=(edge){v,head[u]}; head[u]=cnt; e[++cnt]=(edge){u,head[v]}; head[v]=cnt; } memset(dep,0,sizeof dep); memset(fa,-1,sizeof fa); memset(top,0,sizeof top); fa[dep[1]=top[1]=1]=0; dfs(1);dfs2(1); for(int i=1;i<=n;++i)tree[c[i]].modify(dfn[i],w[i]); while(q--){ scanf("%s",opt); if(opt[0]=='C'){ if(opt[1]=='C'){ int x=readint(),c=readint(); tree[c].modify(dfn[x],tree[::c[x]].deletenode(dfn[x])); ::c[x]=c; }else{ int x=readint(),w=readint(); tree[c[x]].modify(dfn[x],w); } }else{ if(opt[1]=='S'){ int x=readint(),y=readint(); printf("%d ",tree[c[x]].query_sum(x,y)); }else{ int x=readint(),y=readint(); printf("%d ",tree[c[x]].query_max(x,y)); } } } return 0; }