BZOJ3531 [Sdoi2014]旅行 树链剖分 线段树
原文链接:http://www.cnblogs.com/zhouzhendong/p/8080189.html
题目传送门 - BZOJ3531
题意概括
一棵树,n个节点,每一个节点两个值,一个颜色,一个权值。
4种操作:
1. 修改某一个节点的颜色
2. 修改某一个节点的权值
3. 查询两点之间某一颜色的节点最大权值
4. 查询两点之间某一颜色的节点权值和
题解
首先闭着眼睛写上树链剖分。
因为题目里面说了,颜色的值<=100000。
所以我们马上想到的开100000个线段树。
那么修改什么的都是log2n的,时间没问题了。
那么空间显然要炸。
怎么做——动态开点啊。
操作涉及的点很少,所以空间复杂度也是(q+n) log n
然后就水过了、
代码
#include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; const int N=100005,S=N*2*20; bool isd(char ch){return '0'<=ch&&ch<='9';} int read(){ int res=0; char ch=getchar(); while (!isd(ch)) ch=getchar(); while (isd(ch)) res=res*10+ch-48,ch=getchar(); return res; } struct Gragh{ int cnt,y[N*2],nxt[N*2],fst[N]; void clear(){ cnt=0; memset(fst,0,sizeof fst); } void add(int a,int b){ y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt; } }g; int n,q,root[N],w[N],c[N]; int fa[N],son[N],size[N],depth[N],top[N],p[N],ap[N],cnp=0; int ls[S],rs[S],Max[S],sum[S],tot=0; void Get_Gen_Info(int rt,int pre,int d){ size[rt]=1,fa[rt]=pre,son[rt]=-1,depth[rt]=d; for (int i=g.fst[rt];i;i=g.nxt[i]) if (g.y[i]!=pre){ int s=g.y[i]; Get_Gen_Info(s,rt,d+1); size[rt]+=size[s]; if (son[rt]==-1||size[s]>size[son[rt]]) son[rt]=s; } } void Get_Top(int rt,int tp){ top[rt]=tp; ap[p[rt]=++cnp]=rt; if (son[rt]==-1) return; Get_Top(son[rt],tp); for (int i=g.fst[rt];i;i=g.nxt[i]){ int s=g.y[i]; if (s!=fa[rt]&&s!=son[rt]) Get_Top(s,s); } } void pushup(int rt){ Max[rt]=max(Max[ls[rt]],Max[rs[rt]]); sum[rt]=sum[ls[rt]]+sum[rs[rt]]; } void change(int &rt,int L,int R,int pos,int v){ if (!rt) rt=++tot; if (L==R){ Max[rt]=sum[rt]=v; return; } int mid=(L+R)>>1; if (pos<=mid) change(ls[rt],L,mid,pos,v); else change(rs[rt],mid+1,R,pos,v); pushup(rt); } int query(int rt,int L,int R,int xL,int xR,int op){ if (!rt||R<xL||L>xR) return 0; if (xL<=L&&R<=xR) return op?Max[rt]:sum[rt]; int mid=(L+R)>>1; int ansL=query(ls[rt],L,mid,xL,xR,op); int ansR=query(rs[rt],mid+1,R,xL,xR,op); return op?max(ansL,ansR):(ansL+ansR); } int Tquery(int a,int b,int op){ int f1=top[a],f2=top[b],color=c[a],ans=0; while (f1!=f2){ if (depth[f1]<depth[f2]) swap(f1,f2),swap(a,b); int v=query(root[color],1,n,p[f1],p[a],op); ans=op?max(ans,v):(ans+v); a=fa[f1],f1=top[a]; } if (depth[a]>depth[b]) swap(a,b); int v=query(root[color],1,n,p[a],p[b],op); ans=op?max(ans,v):(ans+v); return ans; } int main(){ n=read(),q=read(); for (int i=1;i<=n;i++) w[i]=read(),c[i]=read(); g.clear(); for (int i=1,a,b;i<n;i++){ a=read(),b=read(); g.add(a,b); g.add(b,a); } Get_Gen_Info(1,0,0); Get_Top(1,1); for (int i=1;i<=n;i++) change(root[c[i]],1,n,p[i],w[i]); for (int i=1;i<=q;i++){ char op[5]; int x,y; scanf("%s",op); x=read(),y=read(); if (op[0]=='C'&&op[1]=='C'){ change(root[c[x]],1,n,p[x],0); change(root[c[x]=y],1,n,p[x],w[x]); } if (op[0]=='C'&&op[1]=='W') change(root[c[x]],1,n,p[x],w[x]=y); if (op[0]=='Q'&&op[1]=='S') printf("%d\n",Tquery(x,y,0)); if (op[0]=='Q'&&op[1]=='M') printf("%d\n",Tquery(x,y,1)); } return 0; }