BZOJ1036: [ZJOI2008]树的统计Count
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. 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
树链剖分
点权
单点修改
线段树维护区间最大值,和
#include <bits/stdc++.h> #define ull unsigned long long using namespace std; const int N=1e5+100; int n,m,tot,cnt; int fa[N],last[N]; int son[N],deep[N],dfn[N],num[N],top[N];//重儿子 深度 dfs序 子树规模 所在重链的顶端节点 int sum[N*4],mx[N*4],w[N]; struct orz{ int v,nex;}e[N]; char op[10]; void init() { cnt=0; tot=0; memset(last,0,sizeof(last)); memset(son,-1,sizeof(son)); } void Insert(int x,int y) { cnt++; e[cnt].v=y; e[cnt].nex=last[x]; last[x]=cnt; } void dfs1(int x,int d,int pre) { fa[x]=pre; deep[x]=d; num[x]=1; for (int i=last[x];i;i=e[i].nex) { int v=e[i].v; if (v==fa[x]) continue; dfs1(v,d+1,x); num[x]+=num[v]; if (son[x]==-1 || num[v]>num[son[x]]) son[x]=v; } } void dfs2(int x,int sp) { top[x]=sp; dfn[x]=++tot; if (son[x]==-1) return ; dfs2(son[x],sp); for (int i=last[x];i;i=e[i].nex) { int v=e[i].v; if (v==fa[x]) continue; if (v!=son[x]) dfs2(v,v); } } void PushUp(int s) { sum[s]=sum[s<<1]+sum[s<<1|1]; mx[s]=max(mx[s<<1],mx[s<<1|1]); } void build(int s,int l,int r) { mx[s]=sum[s]=0; if (l==r) return ; int m=(l+r)>>1; build(s<<1,l,m); build(s<<1|1,m+1,r); PushUp(s); } void update(int s,int l,int r,int pos,int val) { if (l==r) { mx[s]=sum[s]=val; return ; } int mid=(l+r)>>1; if (pos<=mid) update(s<<1,l,mid,pos,val); else update(s<<1|1,mid+1,r,pos,val); PushUp(s); } int querymx(int s,int l,int r,int L,int R) { //printf("s=%d,l=%d,r=%d,L=%d,R=%d\n",s,l,r,L,R); if (L<=l&&r<=R) return mx[s]; int mid=(l+r)>>1; int ans=INT_MIN; if (L<=mid) ans=max(ans,querymx(s<<1,l,mid,L,R)); if (R>mid) ans=max(ans,querymx(s<<1|1,mid+1,r,L,R)); return ans; } int querysum(int s,int l,int r,int L,int R) { if (L<=l&&r<=R) return sum[s]; int mid=(l+r)>>1; int ans=0; if (L<=mid) ans+=querysum(s<<1,l,mid,L,R); if (R>mid) ans+=querysum(s<<1|1,mid+1,r,L,R); return ans; } void solve(int op,int x, int y) { if (op==1) { int mx=INT_MIN; while (top[x]!=top[y]) { if (deep[top[x]]<deep[top[y]]) swap(x, y); mx=max(mx,querymx(1,1,n,dfn[top[x]],dfn[x])); x=fa[top[x]]; } if (deep[x]>deep[y]) swap(x,y); mx=max(mx,querymx(1,1,n,dfn[x],dfn[y])); printf("%d\n",mx); } else { int ans=0; while (top[x]!=top[y]) { if (deep[top[x]]<deep[top[y]]) swap(x, y); ans+=querysum(1,1,n,dfn[top[x]],dfn[x]); x=fa[top[x]]; } if (deep[x]>deep[y]) swap(x,y); ans+=querysum(1,1,n,dfn[x],dfn[y]); printf("%d\n",ans); } } int main() { while (scanf("%d",&n)!=EOF) { init(); int u,v; for (int i=1;i<n;i++) { scanf("%d%d",&u,&v); Insert(u,v); Insert(v,u); } dfs1(1,0,0); //cout<<'*'<<endl; dfs2(1,1); build(1,1,n); for (int i=1;i<=n;i++) { scanf("%d",&u); update(1,1,n,dfn[i],u); } scanf("%d",&m); while (m--) { scanf("%s",op); if (op[0]=='C') { scanf("%d%d",&u,&v); update(1,1,n,dfn[u],v); } else { scanf("%d%d",&u,&v); if (op[1]=='M') solve(1,u,v); else solve(2,u,v); } } } return 0; }