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
大致思路:
一道裸的树链剖分,那么久来总结一下树链剖分的整个过程;
- 第一次dfs来确定以下参数:父节点,深度,重链边,size大小
- 第二次dfs来确定:新的编号(也就是映射值),指向链的头结点。
- 建立一个空的线段树
- 遍历一遍点,以点修改的形式把对应的点(也就是之前的映射值)放入线段树,并完成区间信息的合并。
- 对于每一个区间询问,都先看这个区间是否属于一条重链上,如果不是,就先利用头结点和父亲节点把区间放置到同一条链上(这个过程是把头结点中深度较深的那个点先放到线段树上,进行信息的统计,直到两个点的头结点相同)
- 然后把这两个点放到线段树中去统计信息。这么做的原因是:在一条重链上的点在线段树上是连续并且可维护的,所以可以利用线段树去完成。
代码:
这个题目的OJ不知道为什么不能用cin,cout。如果用的话会RE
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=3e4+7; 4 const int INF=1<<30; 5 int weight[maxn],id[maxn],son[maxn],dep[maxn]; 6 int father[maxn],size[maxn],root[maxn]; 7 int idx=0; 8 struct node{ 9 int l,r; 10 int maxx,sum; 11 }tree[maxn<<2]; 12 vector<int> g[maxn]; 13 void dfs(int x,int last,int d) 14 { 15 dep[x]=d; 16 size[x]=1; 17 father[x]=last; 18 son[x]=0; 19 int v; 20 for(int i=0;i<g[x].size();++i){ 21 v=g[x][i]; 22 if(v==last) 23 continue; 24 dfs(v,x,d+1); 25 if(i==0) 26 son[x]=v; 27 else if(size[son[x]]<size[v]) 28 son[x]=v; 29 size[x]+=size[v]; 30 } 31 } 32 void connect(int x,int r) 33 { 34 int v; 35 root[x]=r; 36 id[x]=++idx; 37 if(son[x]!=0){ 38 connect(son[x],r); 39 for(int i=0;i<g[x].size();++i){ 40 v=g[x][i]; 41 if(v!=father[x]&&v!=son[x]) 42 connect(v,v); 43 } 44 } 45 } 46 void build(int l,int r,int k) 47 { 48 if(l>r) 49 return ; 50 tree[k].l=l; 51 tree[k].r=r; 52 if(l==r) 53 return ; 54 int mid=(l+r)>>1; 55 build(l,mid,k<<1); 56 build(mid+1,r,k<<1|1); 57 } 58 void change(int tar,int w,int k) 59 { 60 int l=tree[k].l; 61 int r=tree[k].r; 62 if(l==r){ 63 tree[k].maxx=w; 64 tree[k].sum=w; 65 return ; 66 } 67 int mid=(l+r)>>1; 68 if(tar<=mid) 69 change(tar,w,k<<1); 70 else 71 change(tar,w,k<<1|1); 72 tree[k].maxx=max(tree[k<<1].maxx,tree[k<<1|1].maxx); 73 tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; 74 } 75 int query_max(int ql,int qr,int k) 76 { 77 int l=tree[k].l; 78 int r=tree[k].r; 79 if(ql>r||qr<l) 80 return -INF; 81 if(ql<=l&&qr>=r) 82 return tree[k].maxx; 83 int mid=(l+r)>>1; 84 return max(query_max(ql,qr,k<<1),query_max(ql,qr,k<<1|1)); 85 } 86 int query_sum(int ql,int qr,int k) 87 { 88 int l=tree[k].l; 89 int r=tree[k].r; 90 if(ql>r||qr<l) 91 return 0; 92 if(ql<=l&&qr>=r) 93 return tree[k].sum; 94 int mid=(l+r)>>1; 95 return query_sum(ql,qr,k<<1)+query_sum(ql,qr,k<<1|1); 96 } 97 int Cal_Sum(int qa,int qb) 98 { 99 int sum=0; 100 while(root[qa]!=root[qb]) 101 { 102 if(dep[root[qa]]<dep[root[qb]]) 103 swap(qa,qb); 104 sum+=query_sum(id[root[qa]],id[qa],1); 105 qa=father[root[qa]]; 106 107 } 108 if(id[qa]>id[qb]) 109 swap(qa,qb); 110 sum+=query_sum(id[qa],id[qb],1); 111 return sum; 112 } 113 int Cal_Max(int qa,int qb) 114 { 115 int maxx=-INF; 116 while(root[qa]!=root[qb]) 117 { 118 if(dep[root[qa]]<dep[root[qb]]) 119 swap(qa,qb); 120 maxx=max(maxx,query_max(id[root[qa]],id[qa],1)); 121 qa=father[root[qa]]; 122 } 123 if(id[qa]>id[qb]) 124 swap(qa,qb); 125 maxx=max(maxx,query_max(id[qa],id[qb],1)); 126 return maxx; 127 } 128 int main() 129 { 130 //freopen("in.txt","r",stdin); 131 int n,v,u,q; 132 char cmd[10]; 133 scanf("%d",&n); 134 for(int i=1;i<n;++i){ 135 scanf("%d%d",&u,&v); 136 g[u].push_back(v); 137 g[v].push_back(u); 138 } 139 140 for(int i=1;i<=n;++i) 141 scanf("%d",&weight[i]); 142 dfs(1,1,1); 143 connect(1,1); 144 build(1,n,1); 145 for(int i=1;i<=n;++i) 146 change(id[i],weight[i],1); 147 scanf("%d",&q); 148 for(int i=0;i<q;++i){ 149 scanf("%s%d%d",cmd,&u,&v); 150 if(cmd[0]=='C') 151 change(id[u],v,1); 152 else if(cmd[1]=='S') 153 printf("%d ",Cal_Sum(u,v)); 154 else 155 printf("%d ",Cal_Max(u,v)); 156 } 157 return 0; 158 }