P2590 树的统计
生活随笔
收集整理的這篇文章主要介紹了
P2590 树的统计
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一道樹剖的模板題
首先,由于本人比較懶,就把單點修改寫成了區間修改,其實也沒有有多大區別(關鍵是我不會寫單點修改QAQ)
不得不說,樹剖的碼量比較大,調了一上午才勉強調完。
這道題要求我們支持 單點修改,區間最大值,區間的和 操作。
我們可以對線段樹每個節點 維護一下他的 區間和,以及區間最大值。
其他的就和P3384(樹剖模板題)就差不多了。
還有要注意的點是
1 int ans = -2147483647;
求區間和時 答案一定要賦一個負數,因為這道題每個節點的權值有小于 0 的,不賦的話就會爆。
我這個蒟蒻就在這里卡了好幾回。
最后附上我自己的代碼
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 using namespace std;
5 const int N = 3e4+10;
6 string opt;
7 int n,m,x,y,tot,num;
8 int dfn[N],son[N],head[N],size[N],fa[N];
9 int dep[N],top[N],w[N],a[N];
10 struct node{
11 int to;
12 int net;
13 }e[N*2];
14 void add_(int x,int y){//加邊操作
15 tot++;
16 e[tot].to = y;
17 e[tot].net = head[x];
18 head[x] = tot;
19 }
20 void get_tree(int x){//第一遍dfs求每個點的重兒子
21 dep[x] = dep[fa[x]] + 1;
22 size[x] = 1;
23 for(int i = head[x]; i; i = e[i].net){
24 int to = e[i].to;
25 if(to == fa[x]) continue;
26 fa[to] = x;
27 get_tree(to);
28 size[x] += size[to];
29 if(size[to] > size[son[x]]) son[x] = to;
30 }
31 }
32 void dfs(int x,int topp){//第二遍dfs求每個點的top
33 top[x] = topp;
34 dfn[x] = ++num;//每個點的dfs序,方便之后建線段樹
35 w[dfn[x]] = a[x];
36 if(son[x]) dfs(son[x],topp);
37 for(int i = head[x]; i; i = e[i].net){
38 int to = e[i].to;
39 if(to == fa[x] || to == son[x]) continue;
40 dfs(to,to);
41 }
42 }
43 struct tree{//線段樹常規操作
44 #define l(o) tr[o].lc
45 #define r(o) tr[o].rc
46 #define sum(o) tr[o].sum
47 #define add(o) tr[o].add
48 #define maxn(o) tr[o].maxn
49 struct qxh{
50 int lc,rc;
51 int maxn,add,sum;
52 }tr[N<<2];
53 void up(int o){
54 sum(o) = sum(o*2) + sum(o*2+1);
55 maxn(o) = max(maxn(o*2) , maxn(o*2+1));
56 }
57 void build(int o, int L,int R){//按每個點的dfs序建樹
58 l(o) = L; r(o) = R;
59 if(L == R){
60 sum(o) = maxn(o) = w[L];
61 return ;
62 }
63 int mid = (L + R) / 2;
64 build(o*2,L,mid);
65 build(o*2+1,mid+1,R);
66 up(o);
67 }
68 void chenge(int o,int L,int R,int val){//單點修改變區間修改
69 if(L <= l(o) && R >= r(o)){
70 sum(o) = val;
71 maxn(o) = val;
72 return ;
73 }
74 int mid = (l(o) + r(o)) / 2;
75 if(L <= mid) chenge(o*2,L,R,val);
76 if(R > mid) chenge(o*2+1,L,R,val);
77 up(o);
78 }
79 int ask_sum(int o,int L,int R){//詢問區間的和
80 int ans = 0;
81 if(L <= l(o) && R >= r(o)){
82 return sum(o);
83 }
84 int mid = (l(o) + r(o)) / 2;
85 if(L <= mid) ans += ask_sum(o*2,L,R);
86 if(R > mid) ans += ask_sum(o*2+1,L,R);
87 return ans;
88 }
89 int ask_max(int o,int L,int R){//區間最大值
90 int ans = -2147483647; //一定要初值為負數,否則就會炸掉
91 if(L <= l(o) && R >= r(o)){
92 return maxn(o);
93 }
94 int mid = (l(o) + r(o)) / 2;
95 if(L <= mid) ans = max(ans,ask_max(o*2,L,R));
96 if(R > mid) ans = max(ans,ask_max(o*2+1,L,R));
97 return ans;
98 }
99 }tree;
100 int query_sum(int x,int y){//求樹上路徑的和
101 int ans = 0;
102 while(top[x] != top[y]){//邊跳邊修改
103 if(dep[top[x]] < dep[top[y]]) swap(x,y);
104 ans += tree.ask_sum(1, dfn[top[x]] , dfn[x]);
105 x = fa[top[x]];
106 }
107 if(dep[x] > dep[y]) swap(x,y);//使dfn[x] ~dfn[y]這一段區間的序號保持有序
108 ans += tree.ask_sum(1,dfn[x],dfn[y]);
109 return ans;
110 }
111 int query_max(int x,int y){//求樹上路徑和,同上
112 int ans = -2147483647;//賦初值。。。。
113 while(top[x] != top[y]){
114 if(dep[top[x]] < dep[top[y]]) swap(x,y);
115 ans = max(ans,tree.ask_max(1,dfn[top[x]],dfn[x]));
116 x = fa[top[x]];
117 }
118 if(dep[x] > dep[y]) swap(x,y);
119 ans = max(ans,tree.ask_max(1,dfn[x],dfn[y]));
120 return ans;
121 }
122 int main(){
123 scanf("%d",&n);
124 for(int i = 1; i <= n-1; i++){
125 scanf("%d%d",&x,&y);
126 add_(x,y);//建雙向邊
127 add_(y,x);
128 }
129 for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
130 get_tree(1);//預處理
131 dfs(1,1);
132 tree.build(1,1,n);
133 scanf("%d",&m);
134 while(m--){
135 cin>>opt;
136 scanf("%d%d",&x,&y);
137 if(opt == "CHANGE"){
138 tree.chenge(1,dfn[x],dfn[x],y);
139 }
140 if(opt == "QMAX"){
141 printf("%d\n",query_max(x,y));
142 }
143 if(opt == "QSUM"){
144 printf("%d\n",query_sum(x,y));
145 }
146 }
147 return 0;
148 }
代碼寫的比較丑QAQ ,不喜勿噴。。。。
其實樹剖的大部分都是模板題,只要記住兩遍dfs就差不多了。
樹剖套線段樹就是將樹剖的模板和線段樹的模板湊到一起,每次修改或查詢的時候對每條重鏈或輕鏈所在的線段樹有序區間進行修改或查詢。
樹剖也就這么多東西。。。
這道題也就結束了,如果看不懂的可以看看Treaker (我們上屆一位巨佬,會各種奇奇怪怪的樹)的題解,他寫的也挺好的 %%%%%
想練習樹剖的可以做一下下面這幾道題
這些都是我們可愛的Treaker學長留的好題(毒瘤題,每道題都要調很久)。。。QAQ
本篇題解到這里就結束了。撒花??ヽ(°▽°)ノ?
樹剖未完待續。。。。。QAQ
總結
以上是生活随笔為你收集整理的P2590 树的统计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP base64_decode+gz
- 下一篇: MediaInfo源代码分析 1:整体结