1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 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
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
【思路】
树链剖分,线段树
线段树:区间查询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 ",query(u,v,0)); 104 else printf("%d ",query(u,v,1)); 105 } 106 return 0; 107 }