动态开点的树链剖分qwq。
跟小奇的花园一模一样,不做过多讲解。
#include<cstdio> #include<cstring> #include<cctype> #include<cstdlib> #include<algorithm> #define maxn 100010 #define mid ((l+r)>>1) #define check(x) if(x==0) x=++tot; using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch==‘-‘) f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-‘0‘; ch=getchar(); } return num*f; } struct Edge{ int next,to; }edge[maxn*3]; int head[maxn],num; inline void add(int from,int to){ edge[++num]=(Edge){head[from],to}; head[from]=num; } int dfn[maxn]; int back[maxn],cnt; int sum[maxn*100],tot; int mav[maxn*100]; int root[maxn]; int ls[maxn*100]; int rs[maxn*100]; int top[maxn]; int size[maxn]; int son[maxn]; int deep[maxn]; int father[maxn]; int d[maxn]; int q[maxn]; int n,m; void find(int x,int fa){ size[x]=1;deep[x]=deep[fa]+1; for(int i=head[x];i;i=edge[i].next){ int to=edge[i].to; if(to==fa) continue; father[to]=x; find(to,x); size[x]+=size[to]; if(son[x]==0||size[son[x]]<size[to]) son[x]=to; } } void unionn(int x,int Top){ dfn[x]=++cnt; back[cnt]=x; top[x]=Top; if(son[x]==0) return; unionn(son[x],Top); for(int i=head[x];i;i=edge[i].next){ int to=edge[i].to; if(to==father[x]||to==son[x]) continue; unionn(to,to); } } inline void pushup(int rt){ sum[rt]=sum[ls[rt]]+sum[rs[rt]]; mav[rt]=max(mav[ls[rt]],mav[rs[rt]]); } void update(int o,int num,int l,int r,int &rt){ check(rt); if(l==r){ sum[rt]=num; mav[rt]=num; return; } if(o<=mid) update(o,num,l,mid,ls[rt]); else update(o,num,mid+1,r,rs[rt]); pushup(rt); return; } int quemax(int from,int to,int l,int r,int &rt){ if(rt==0) return 0; if(from<=l&&to>=r) return mav[rt]; int ans=0; if(from<=mid) ans=max(ans,quemax(from,to,l,mid,ls[rt])); if(to>mid) ans=max(ans,quemax(from,to,mid+1,r,rs[rt])); return ans; } int quesum(int from,int to,int l,int r,int &rt){ if(rt==0) return 0; if(from<=l&&to>=r) return sum[rt]; int ans=0; if(from<=mid) ans+=quesum(from,to,l,mid,ls[rt]); if(to>mid) ans+=quesum(from,to,mid+1,r,rs[rt]); return ans; } int askmax(int from,int to,int val){ int ans=0; while(top[from]!=top[to]){ if(deep[top[from]]<deep[top[to]]) swap(from,to); ans=max(ans,quemax(dfn[top[from]],dfn[from],1,n,root[val])); from=father[top[from]]; } if(deep[from]>=deep[to]) swap(from,to); ans=max(ans,quemax(dfn[from],dfn[to],1,n,root[val])); return ans; } int asksum(int from,int to,int val){ int ans=0; while(top[from]!=top[to]){ if(deep[top[from]]<deep[top[to]]) swap(from,to); ans+=quesum(dfn[top[from]],dfn[from],1,n,root[val]); from=father[top[from]]; } if(deep[from]>=deep[to]) swap(from,to); ans+=quesum(dfn[from],dfn[to],1,n,root[val]); return ans; } void chancol(int pos,int val){ update(dfn[pos],0,1,n,root[q[pos]]); update(dfn[pos],d[pos],1,n,root[val]); q[pos]=val; } void channum(int pos,int val){ update(dfn[pos],val,1,n,root[q[pos]]); d[pos]=val; } int main(){ n=read(),m=read(); for(int i=1;i<=n;++i){ d[i]=read();q[i]=read(); } for(int i=1;i<n;++i){ int x=read(),y=read(); add(x,y); add(y,x); } find(1,1); unionn(1,1); for(int i=1;i<=n;++i) update(dfn[i],d[i],1,n,root[q[i]]); for(int i=1;i<=m;++i){ char c[10]; scanf("%s",c); if(c[0]==‘C‘){ if(c[1]==‘C‘){ int x=read(),y=read(); chancol(x,y); } else{ int x=read(),y=read(); channum(x,y); } } else if(c[0]==‘Q‘){ if(c[1]==‘S‘){ int x=read(),y=read(); printf("%d\n",asksum(x,y,q[x])); } else{ int x=read(),y=read(); printf("%d\n",askmax(x,y,q[x])); } } } return 0; }
https://www.luogu.org/problemnew/show/P3313
原文地址:https://www.cnblogs.com/cellular-automaton/p/8352808.html
时间: 2024-10-30 11:46:02