Spoj375 Qtree
给一棵共有 n(n · 10000) 个结点的树, 每条边都有一个权值, 要求维护一个数据结构, 支持如下操作:
1. 修改某条边的权值;
2. 询问某两个结点之间的唯一通路上的最大边权.
其中操作的总次数为 q.
Sample Input
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
Sample Output
1
3
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; int sum,maxx,n,m,f[30001],pre[100001],nxt[100001],h[30001],now,size[100001],dep[100001],id[30001],top[30001],cnt,y[30001],z[30001],x[30001]; struct oo { int a,b,mx; } s[100001]; char p[9]; void dfs(int x) { size[x]=1; for(int i=h[x];i;i=nxt[i]) { if(pre[i]==f[x]) continue; dep[pre[i]]=dep[x]+1; f[pre[i]]=x; dfs(pre[i]); size[x]+=size[pre[i]]; } } void dfs2(int x,int f) { int k=0; id[x]=++cnt;//x在线段树中的位置 top[x]=f;//标记top结记 for(int i=h[x];i;i=nxt[i]) // 找出重儿子 if(size[pre[i]]>size[k]&&dep[pre[i]]>dep[x]) k=pre[i]; if(!k) return ; dfs2(k,f); for(int i=h[x];i;i=nxt[i]) if(dep[pre[i]]>dep[x]&&pre[i]!=k) dfs2(pre[i],pre[i]); } void ins(int x,int y) { pre[++now]=y; nxt[now]=h[x]; h[x]=now; } void build(int x,int l,int r) { s[x].a=l; s[x].b=r; if(l==r) { s[x].mx=-1e9; return ; } build(x<<1,l,l+r>>1); build(x<<1|1,(l+r>>1)+1,r); s[x].mx=max(s[x<<1].mx,s[x<<1|1].mx); } void get(int x,int l,int r) { if(s[x].a>=l&&r>=s[x].b) maxx=max(s[x].mx,maxx); else { int mid=s[x].a+s[x].b>>1; if(l<=mid) get(x<<1,l,r); if(r>mid) get(x<<1|1,l,r); } } void qmax(int x,int y) { maxx=-1e9; while(top[x]!=top[y])//当没有在一条重链上时 { if(dep[top[x]]<dep[top[y]]) swap(x,y); get(1,id[top[x]],id[x]); x=f[top[x]]; } if(id[x]>id[y]) swap(x,y); get(1,id[x]+1,id[y]); } void change(int x,int l,int v) { if(s[x].a==s[x].b) { s[x].mx=v; return ; } int mid=s[x].a+s[x].b>>1; if(l<=mid) change(x<<1,l,v); else change(x<<1|1,l,v); s[x].mx=max(s[x<<1].mx,s[x<<1|1].mx); } int T; int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); memset(h,0,sizeof h); now=0;cnt=0; for(int i=1;i<n;i++) { scanf("%d%d%d",&x[i],&y[i],&z[i]); ins(x[i],y[i]); ins(y[i],x[i]); } dfs(1); dfs2(1,1); build(1,1,n); for(int i=1;i<n;i++) { int a=id[x[i]],b=id[y[i]]; if(dep[x[i]]>dep[y[i]]) //将边权放到点上,要放到这条边的儿子点上 //因为某个点可以会有多个子结点,放父亲点,就会出问题了 change(1,a,z[i]),z[i]=a;//记下第i条边在线段树中的位置 else change(1,b,z[i]),z[i]=b; } while(1) { int a,b; scanf("%s",p+1); if(p[1]=='Q') { scanf("%d%d",&a,&b); qmax(a,b); printf("%d ",maxx); } if(p[1]=='D')break; if(p[1]=='C') scanf("%d%d",&a,&b),change(1,z[a],b); } } }