http://www.lydsy.com/JudgeOnline/problem.php?id=1036
树链剖分板子题
#include<cstdio> #include<iostream> #include<algorithm> #define N 30001 using namespace std; int front[N],to[N<<1],nxt[N<<1],tot; int n,val[N]; int siz[N],fa[N],dep[N]; int id[N],dy[N],bl[N]; int mx[N<<2],sum[N<<2]; int ans; void read(int &x) { x=0; int f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } x*=f; } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; } void dfs1(int x,int y) { siz[x]=1; for(int i=front[x];i;i=nxt[i]) if(to[i]!=y) { dep[to[i]]=dep[x]+1; fa[to[i]]=x; dfs1(to[i],x); siz[x]+=siz[to[i]]; } } void dfs2(int x,int top) { bl[x]=top; id[x]=++tot; dy[tot]=x; int y=0; for(int i=front[x];i;i=nxt[i]) { if(to[i]==fa[x]) continue; if(siz[to[i]]>siz[y]) y=to[i]; } if(y) dfs2(y,top); for(int i=front[x];i;i=nxt[i]) { if(to[i]==fa[x] || to[i]==y) continue; dfs2(to[i],to[i]); } } void build(int k,int l,int r) { if(l==r) { mx[k]=sum[k]=val[dy[l]]; return; } int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); mx[k]=max(mx[k<<1],mx[k<<1|1]); sum[k]=sum[k<<1]+sum[k<<1|1]; } void change(int k,int l,int r,int pos,int w) { if(l==r) { mx[k]=sum[k]=w; return; } int mid=l+r>>1; if(pos<=mid) change(k<<1,l,mid,pos,w); else change(k<<1|1,mid+1,r,pos,w); mx[k]=max(mx[k<<1],mx[k<<1|1]); sum[k]=sum[k<<1]+sum[k<<1|1]; } void query(int k,int l,int r,int opl,int opr,bool ty) { if(l>=opl && r<=opr) { if(!ty) ans=max(ans,mx[k]); else ans+=sum[k]; return; } int mid=l+r>>1; if(opl<=mid) query(k<<1,l,mid,opl,opr,ty); if(opr>mid) query(k<<1|1,mid+1,r,opl,opr,ty); } void solve(int u,int v,bool ty) { if(!ty) ans=-1e7; else ans=0; while(bl[u]!=bl[v]) { if(dep[bl[u]]<dep[bl[v]]) swap(u,v); query(1,1,n,id[bl[u]],id[u],ty); u=fa[bl[u]]; } if(dep[u]>dep[v]) swap(u,v); query(1,1,n,id[u],id[v],ty); cout<<ans<<' '; } int main() { int u,v; read(n); for(int i=1;i<n;++i) read(u),read(v),add(u,v); for(int i=1;i<=n;++i) read(val[i]); dfs1(1,0); tot=0; dfs2(1,1); build(1,1,n); int m; char c[7]; read(m); while(m--) { scanf("%s",c); read(u); read(v); if(c[0]=='C') change(1,1,n,id[u],v); else if(c[1]=='M') solve(u,v,0); else solve(u,v,1); } }
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 19421 Solved: 7912
[Submit][Status][Discuss]
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16
1
2
2
10
6
5
6
5
16