题解:
解法1:
树链剖分一下,对每条链建立一颗Splay
以宗教为第一关键字,深度为第二关键字建立
查询相当于Splay的一个区间
修改相当于删除一个节点,加入一个节点
O(nlog^2n) O(n);
解法2:
树链剖分一下,对每条链建立maxc棵权值线段树,动态开点
O(nlog^2n) O(nlogn)
问题:自己还没写过动态开点线段树
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=300009; const int inf=1000000000; inline int max(int a,int b){ if(a>b)return a; else return b; } int n,m; int w[maxn],c[maxn]; int father[maxn],depth[maxn],siz[maxn]; int idp[maxn],rt[maxn],ref[maxn],hson[maxn],tp[maxn]; int cntedge; int head[maxn]; int to[maxn<<1],nex[maxn<<1]; void Addedge(int x,int y){ nex[++cntedge]=head[x]; to[cntedge]=y; head[x]=cntedge; } int nn; int fa[maxn],ch[maxn][2],sum[maxn],mx[maxn]; inline void pushup(int x){ sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+w[x]; mx[x]=max(w[x],max(mx[ch[x][0]],mx[ch[x][1]])); } inline int son(int x){ if(ch[fa[x]][1]==x)return 1; else return 0; } inline void Rotate(int &root,int x){ int y=fa[x]; int z=fa[y]; int b=son(x),c=son(y); int a=ch[x][b^1]; if(z)ch[z][c]=x; else root=x; fa[x]=z; if(a)fa[a]=y; ch[y][b]=a; fa[y]=x;ch[x][b^1]=y; pushup(y);pushup(x); } void Splay(int &root,int x,int i){ while(fa[x]!=i){ int y=fa[x]; int z=fa[y]; if(z==i){ Rotate(root,x); }else{ if(son(x)==son(y)){ Rotate(root,y);Rotate(root,x); }else{ Rotate(root,x);Rotate(root,x); } } } } inline int cmp(int x,int y){ if(c[x]<c[y])return -1; if(c[x]>c[y])return 1; if(depth[x]<depth[y])return -1; if(depth[x]>depth[y])return 1; return 0; } void Ins(int &root,int p){ int x=root,y=0; while(x){ y=x; if(cmp(x,p)>0)x=ch[x][0]; else x=ch[x][1]; } x=p; fa[x]=y;ch[x][0]=ch[x][1]=0; sum[x]=mx[x]=w[x]; if(y){ if(cmp(x,y)<0)ch[y][0]=x; else ch[y][1]=x; }else{ root=x; } Splay(root,x,0); } void Del(int &root,int x){ Splay(root,x,0); if(ch[x][0]==0){ root=ch[x][1];fa[ch[x][1]]=0; }else if(ch[x][1]==0){ root=ch[x][0];fa[ch[x][0]]=0; }else{ int p=ch[x][0]; while(ch[p][1])p=ch[p][1]; Splay(root,p,x); ch[p][1]=ch[x][1];fa[ch[x][1]]=p; root=p;fa[p]=0;pushup(p); } } void check(int x){ if(ch[x][0])check(ch[x][0]); cout<<c[x]<<‘ ‘<<depth[x]<<endl; if(ch[x][1])check(ch[x][1]); } int Getpre(int root,int p){ int x=root,ret=0; while(x){ if(cmp(x,p)<0){ ret=x; x=ch[x][1]; }else{ x=ch[x][0]; } } return ret; } int Getsuf(int root,int p){ int x=root,ret=0; while(x){ if(cmp(x,p)>0){ ret=x; x=ch[x][0]; }else{ x=ch[x][1]; } } return ret; } void Dfs(int now,int ff){ father[now]=ff; depth[now]=depth[ff]+1; siz[now]=1; for(int i=head[now];i;i=nex[i]){ if(to[i]==ff)continue; Dfs(to[i],now); siz[now]+=siz[to[i]]; if(siz[to[i]]>siz[hson[now]])hson[now]=to[i]; } } int dfsclock; void Dfs2(int now,int toppoint){ idp[now]=++dfsclock; ref[dfsclock]=now; tp[now]=toppoint; Ins(rt[toppoint],now); if(!hson[now])return; Dfs2(hson[now],toppoint); for(int i=head[now];i;i=nex[i]){ if(to[i]==father[now])continue; if(to[i]==hson[now])continue; Dfs2(to[i],to[i]); } } void ChangeC(int x,int y){ Del(rt[tp[x]],x); c[x]=y; Ins(rt[tp[x]],x); } void ChangeW(int x,int y){ Splay(rt[tp[x]],x,0); w[x]=y;pushup(x); } int QueryM(int u,int v){ int tu=tp[u]; int tv=tp[v]; int ret=0; c[nn]=c[u]; while(tu!=tv){ if(depth[tu]<depth[tv]){ swap(tu,tv);swap(u,v); } depth[nn]=depth[u]; int p=Getsuf(rt[tu],nn); Splay(rt[tu],p,0); depth[nn]=depth[tu]; p=Getpre(rt[tu],nn); Splay(rt[tu],p,rt[tu]); ret=max(ret,mx[ch[ch[rt[tu]][0]][1]]); u=father[tu];tu=tp[u]; } if(depth[u]>depth[v])swap(u,v); depth[nn]=depth[v]; int p=Getsuf(rt[tp[u]],nn); Splay(rt[tp[u]],p,0); depth[nn]=depth[u]; p=Getpre(rt[tp[u]],nn); Splay(rt[tp[u]],p,rt[tp[u]]); ret=max(ret,mx[ch[ch[rt[tp[u]]][0]][1]]); return ret; } int QueryS(int u,int v){ int tu=tp[u]; int tv=tp[v]; int ret=0; c[nn]=c[u]; while(tu!=tv){ if(depth[tu]<depth[tv]){ swap(tu,tv);swap(u,v); } depth[nn]=depth[u]; int p=Getsuf(rt[tu],nn); Splay(rt[tu],p,0); depth[nn]=depth[tu]; p=Getpre(rt[tu],nn); Splay(rt[tu],p,rt[tu]); ret+=sum[ch[ch[rt[tu]][0]][1]]; u=father[tu];tu=tp[u]; } if(depth[u]>depth[v])swap(u,v); depth[nn]=depth[v]; int p=Getsuf(rt[tp[u]],nn); Splay(rt[tp[u]],p,0); depth[nn]=depth[u]; p=Getpre(rt[tp[u]],nn); Splay(rt[tp[u]],p,rt[tp[u]]); ret+=sum[ch[ch[rt[tp[u]]][0]][1]]; return ret; } int main(){ // freopen("travel.in","r",stdin); // freopen("travel.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)scanf("%d%d",&w[i],&c[i]); for(int i=1;i<=n-1;++i){ int x,y; scanf("%d%d",&x,&y); Addedge(x,y); Addedge(y,x); } Dfs(1,0); Dfs2(1,1); nn=n; for(int i=1;i<=n;++i){ if(tp[i]==i){ c[++nn]=-inf; c[++nn]=inf; Ins(rt[i],nn-1); Ins(rt[i],nn); } } ++nn; while(m--){ char opty[3]; int x,y; scanf("%s",opty); scanf("%d%d",&x,&y); if(opty[1]==‘C‘){ ChangeC(x,y); } if(opty[1]==‘W‘){ ChangeW(x,y); } if(opty[1]==‘M‘){ printf("%d\n",QueryM(x,y)); } if(opty[1]==‘S‘){ printf("%d\n",QueryS(x,y)); } } return 0; }