bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

 

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 10677  Solved: 4313
[Submit][Status][Discuss]

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

Sample Output

4
1
2
2
10
6
5
6
5
16

 

【思路】

       树链剖分,线段树

       线段树:区间查询max sum ,单点操作 set。

       注意一下负数就行了=-=。

 

【代码】

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<iostream>
  5 #include<algorithm>
  6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
  7 using namespace std;
  8 
  9 const int N = 50000+10;
 10 const int INF = 1e9;
 11 
 12 struct Node {
 13     int mx,sum;
 14     Node() {mx=-INF,sum=0;}
 15 }T[N<<1];
 16 
 17 int n,q,z;
 18 char s[20];
 19 vector<int> g[N];
 20 //INIT
 21 int top[N],son[N],dep[N],fa[N],siz[N],w[N];
 22 void dfs1(int u) {
 23     son[u]=0; siz[u]=1;
 24     for(int i=0;i<g[u].size();i++) {
 25         int v=g[u][i];
 26         if(v!=fa[u]) {
 27             fa[v]=u , dep[v]=dep[u]+1;
 28             dfs1(v);
 29             siz[u]+=siz[v];
 30             if(siz[v]>siz[son[u]]) son[u]=v;
 31         }
 32     }
 33 }
 34 void dfs2(int u,int tp) {
 35     top[u]=tp; w[u]=++z;
 36     if(son[u]) dfs2(son[u],tp);
 37     for(int i=0;i<g[u].size();i++) {
 38         int v=g[u][i];
 39         if(v!=fa[u] && v!=son[u]) dfs2(v,v);
 40     }
 41 }
 42 //SEGMENT TREE
 43 void update(int u,int L,int R,int r,int x) {
 44     if(L==R) T[u].mx=T[u].sum=x;
 45     else {
 46         int M=(L+R)>>1,lc=u<<1,rc=lc|1;
 47         if(r<=M) update(lc,L,M,r,x);
 48         else update(rc,M+1,R,r,x);
 49         T[u].mx=max(T[lc].mx,T[rc].mx);
 50         T[u].sum=T[lc].sum+T[rc].sum;
 51     }
 52 }
 53 int qsum,qmx;
 54 void query(int u,int L,int R,int l,int r) {
 55     if(l<=L && R<=r)
 56         qsum+=T[u].sum , qmx=max(qmx,T[u].mx);
 57     else {
 58         int M=(L+R)>>1;
 59         if(l<=M) query(u<<1,L,M,l,r);
 60         if(M<r) query(u<<1|1,M+1,R,l,r);
 61     }
 62 }
 63 //树链剖分
 64 int query(int u,int v,int flag) {
 65     int sum=0,mx=-INF;
 66     while(top[u]!=top[v]) {
 67         if(dep[top[u]]<dep[top[v]]) swap(u,v);
 68         qsum=0 , qmx=-INF;
 69         query(1,1,z,w[top[u]],w[u]);
 70         sum+=qsum , mx=max(mx,qmx);
 71         u=fa[top[u]];
 72     }
 73     if(dep[u]>dep[v]) swap(u,v);
 74     qsum=0 , qmx=-INF;
 75     query(1,1,z,w[u],w[v]);
 76     sum+=qsum , mx=max(mx,qmx);
 77     return flag? sum:mx;
 78 }
 79 
 80 void read(int& x) {
 81     char c=getchar(); int f=1; x=0;
 82     while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
 83     while(isdigit(c)) x=x*10+c-'0',c=getchar();
 84     x*=f;
 85 }
 86 int main() {
 87     read(n);
 88     int u,v,x;
 89     FOR(i,1,n-1) {
 90         read(u),read(v);
 91         g[u].push_back(v);
 92         g[v].push_back(u);
 93     }
 94     dfs1(1),dfs2(1,1);
 95     FOR(i,1,n)
 96         read(x) , update(1,1,z,w[i],x);
 97     read(q);
 98     while(q--) {
 99         scanf("%s",s);
100         read(u),read(v);
101         if(s[0]=='C')  update(1,1,z,w[u],v);
102         else
103             if(s[1]=='M') printf("%d\n",query(u,v,0));
104             else printf("%d\n",query(u,v,1));
105     }
106     return 0;
107 }

 

你可能感兴趣的:(bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树))