1. 程式人生 > >BZOJ 1036: [ZJOI2008]樹的統計Count (樹鏈剖分+線段樹)

BZOJ 1036: [ZJOI2008]樹的統計Count (樹鏈剖分+線段樹)

題目概述:

n個結點的樹,點有點權.有三種操作:1.單點修改點權,區間詢問和,區間詢問最值.

題目分析:

先用樹鏈剖分將樹剖分成多條鏈,再用線段樹維護.

程式碼:

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

const int maxn=30000+10;
const int maxm=60000+10;
const int INF=100000;

int fir[maxn],nxt[maxm],to[maxm],ecnt;

void add_edge(int
u,int v) { nxt[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v; nxt[++ecnt]=fir[v];fir[v]=ecnt;to[ecnt]=u; } //樹鏈剖分 int fa[maxn],sz[maxn],son[maxn]; void dfs1(int u,int p) { sz[u]=1;fa[u]=p; for(int i=fir[u];i;i=nxt[i]) if(to[i]!=p) { int v=to[i]; dfs1(v,u); sz[u]+=sz[v]; if
(sz[v]>sz[son[u]]) son[u]=v; } } int top[maxn],dep[maxn],idx[maxn],id; void dfs2(int u,int t,int d) { top[u]=t;dep[u]=d;idx[u]=++id; if(son[u]) dfs2(son[u],t,d+1); for(int i=fir[u];i;i=nxt[i]) if(to[i]!=fa[u]&&to[i]!=son[u]) dfs2(to[i],to[i],d+1); } //線段樹 #define lc (x<<1)
#define rc (x<<1|1) #define mid ((l+r)>>1) int val[maxn],maxs[maxn<<2],sum[maxn<<2]; void up(int x) { maxs[x]=max(maxs[lc],maxs[rc]); sum[x]=sum[lc]+sum[rc]; } void build(int x,int l,int r) { if(l==r) maxs[x]=sum[x]=val[l]; else { build(lc,l,mid); build(rc,mid+1,r); up(x); } } void update(int x,int l,int r,int q,int v) { if(l==r&&l==q) maxs[x]=sum[x]=v; else { if(q<=mid) update(lc,l,mid,q,v); else update(rc,mid+1,r,q,v); up(x); } } int query(int x,int l,int r,int ql,int qr,int k)//k 1 sum 0 max { if(ql<=l&&r<=qr) return k?sum[x]:maxs[x]; int L=k?0:-INF,R=k?0:-INF; if(ql<=mid) L=query(lc,l,mid,ql,qr,k); if(qr>mid) R=query(rc,mid+1,r,ql,qr,k); return k?L+R:max(L,R); } int N; int solve(int x,int y,int k)//k 1 sum 0 max { int ret=k?0:-INF; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); if(k) ret+=query(1,1,N,idx[top[x]],idx[x],k); else ret=max(ret,query(1,1,N,idx[top[x]],idx[x],k)); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); if(k) ret+=query(1,1,N,idx[x],idx[y],k); else ret=max(ret,query(1,1,N,idx[x],idx[y],k)); return ret; } char op[10]; int main() { scanf("%d",&N); for(int u,v,i=1;i<N;i++) { scanf("%d%d",&u,&v); add_edge(u,v); } dfs1(1,1); dfs2(1,1,1); for(int i=1;i<=N;i++) scanf("%d",&val[idx[i]]); build(1,1,N); int Q,a,b; scanf("%d",&Q); while(Q--) { scanf("%s%d%d",op,&a,&b); if(op[0]=='C') update(1,1,N,idx[a],b); else printf("%d\n",solve(a,b,op[1]=='S'?1:0)); } return 0; }