生活随笔
收集整理的這篇文章主要介紹了
[HAOI2015]树上操作
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目大意:
給你一棵n個點的樹,以1為根,每個點都有一個點權,要求進行如下操作:
1.將x這個點的點權加上a;
2.將以x這個點為根的子樹中每個點的點權加上a;
3.查詢從x到根的路徑的點權和。
思路:
樹鏈剖分。
對于第2種操作,我們不難發現一個子樹中結點在線段樹中的編號一定是連續的。
于是修改子樹的操作就是線段樹上修改id[x]~id[x]+size[x]-1的操作。
1 #include<cstdio>
2 #include<cctype>
3 #include<vector>
4 typedef
long long int64;
5 inline
int getint() {
6 register
char ch;
7 register
bool neg=
false;
8 while(!isdigit(ch=getchar()))
if(ch==
'-') neg=
true;
9 register
int x=ch^
'0';
10 while(isdigit(ch=getchar())) x=(((x<<
2)+x)<<
1)+(ch^
'0');
11 return neg?-
x:x;
12 }
13 const int N=
100001;
14 std::vector<
int>
e[N];
15 inline
void add_edge(
const int &u,
const int &
v) {
16 e[u].push_back(v);
17 e[v].push_back(u);
18 }
19 int n,size[N],par[N],dep[N],id[N],son[N],top[N],w[N],node[N];
20 void dfs1(
const int &x,
const int &
par) {
21 ::par[x]=
par;
22 dep[x]=dep[par]+
1;
23 size[x]=
1;
24 for(unsigned i=
0;i<e[x].size();i++
) {
25 const int &y=
e[x][i];
26 if(y==par)
continue;
27 dfs1(y,x);
28 size[x]+=
size[y];
29 if(size[y]>size[son[x]]) son[x]=
y;
30 }
31 }
32 void dfs2(
const int &
x) {
33 id[x]=++id[
0];
34 node[id[x]]=
x;
35 if(x==
son[par[x]]) {
36 top[x]=
top[par[x]];
37 }
else {
38 top[x]=
x;
39 }
40 if(son[x]) dfs2(son[x]);
41 for(unsigned i=
0;i<e[x].size();i++
) {
42 const int &y=
e[x][i];
43 if(y==par[x]||y==son[x])
continue;
44 dfs2(y);
45 }
46 }
47 class SegmentTree {
48 #define _left <<1
49 #define _right <<1|1
50 private:
51 int64 val[N<<
2],tag[N<<
2];
52 void push_up(
const int &
p) {
53 val[p]=val[p _left]+
val[p _right];
54 }
55 int size(
const int &b,
const int &e)
const {
56 return e-b+
1;
57 }
58 void push_down(
const int &p,
const int &b,
const int &
e) {
59 const int mid=(b+e)>>
1;
60 val[p _left]+=tag[p]*
size(b,mid);
61 val[p _right]+=tag[p]*size(mid+
1,e);
62 tag[p _left]+=
tag[p];
63 tag[p _right]+=
tag[p];
64 tag[p]=
0;
65 }
66 public:
67 void build(
const int &p,
const int &b,
const int &
e) {
68 if(b==
e) {
69 val[p]=
w[node[b]];
70 return;
71 }
72 const int mid=(b+e)>>
1;
73 build(p _left,b,mid);
74 build(p _right,mid+
1,e);
75 push_up(p);
76 }
77 void modify(
const int &p,
const int &b,
const int &e,
const int &l,
const int &r,
const int &
x) {
78 if(b==l&&e==
r) {
79 val[p]+=(int64)x*
size(b,e);
80 tag[p]+=
x;
81 return;
82 }
83 const int mid=(b+e)>>
1;
84 push_down(p,b,e);
85 if(l<=
mid) modify(p _left,b,mid,l,std::min(mid,r),x);
86 if(r>mid) modify(p _right,mid+
1,e,std::max(mid+
1,l),r,x);
87 push_up(p);
88 }
89 int64 query(
const int &p,
const int &b,
const int &e,
const int &l,
const int &
r) {
90 if(b==l&&e==
r) {
91 return val[p];
92 }
93 const int mid=(b+e)>>
1;
94 push_down(p,b,e);
95 int64 ret=
0;
96 if(l<=mid) ret+=
query(p _left,b,mid,l,std::min(mid,r));
97 if(r>mid) ret+=query(p _right,mid+
1,e,std::max(mid+
1,l),r);
98 return ret;
99 }
100 #undef _left
101 #undef _right
102 };
103 SegmentTree t;
104 inline int64 query(
int x) {
105 int64 ret=
0;
106 while(x) {
107 ret+=t.query(
1,
1,n,id[top[x]],id[x]);
108 x=
par[top[x]];
109 }
110 return ret;
111 }
112 int main() {
113 n=
getint();
114 const int m=
getint();
115 for(register
int i=
1;i<=n;i++
) {
116 w[i]=
getint();
117 }
118 for(register
int i=
1;i<n;i++
) {
119 add_edge(getint(),getint());
120 }
121 dfs1(
1,
0);
122 dfs2(
1);
123 t.build(
1,
1,n);
124 for(register
int i=
0;i<m;i++
) {
125 const int op=getint(),x=
getint();
126 if(op==
1) {
127 t.modify(
1,
1,n,id[x],id[x],getint());
128 }
129 if(op==
2) {
130 t.modify(
1,
1,n,id[x],id[x]+size[x]-
1,getint());
131 }
132 if(op==
3) {
133 printf(
"%lld\n",query(x));
134 }
135 }
136 return 0;
137 }
View Code 題目求的是點到根路徑上的權值和,那么修改單點對整棵子樹所有結點的詢問都有貢獻。
給整棵子樹增加權值顯然也會對整棵子樹的詢問產生貢獻。
若v是u的子樹中的一個點,對結點u為根的子樹的每一個結點權值增加a,相當于給針對v的詢問答案增加了(dis(u,v)+1)a。
考慮將樹“壓扁”,求出樹的DFS序。 對于結點u的子樹,DFS序范圍是dfn[u]~dfn[u]+size[u]-1。
用線段樹維護兩個值x和y,分別代表需要乘dis的權值和不需要乘dis的權值,詢問時返回dep[u]*x[u]+y[u]即可。
1 #include<cstdio>
2 #include<cctype>
3 #include<vector>
4 typedef
long long int64;
5 inline
int getint() {
6 register
char ch;
7 register
bool neg=
false;
8 while(!isdigit(ch=getchar()))
if(ch==
'-') neg=
true;
9 register
int x=ch^
'0';
10 while(isdigit(ch=getchar())) x=(((x<<
2)+x)<<
1)+(ch^
'0');
11 return neg?-
x:x;
12 }
13 const int N=
100001;
14 int w[N],dfn[N],size[N],dep[N];
15 std::vector<
int>
e[N];
16 inline
void add_edge(
const int &u,
const int &
v) {
17 e[u].push_back(v);
18 e[v].push_back(u);
19 }
20 void dfs(
const int &x,
const int &
par) {
21 size[x]=
1;
22 dfn[x]=++dfn[
0];
23 dep[x]=dep[par]+
1;
24 for(unsigned i=
0;i<e[x].size();i++
) {
25 const int &y=
e[x][i];
26 if(y==par)
continue;
27 dfs(y,x);
28 size[x]+=
size[y];
29 }
30 }
31 class SegmentTree {
32 #define _left <<1
33 #define _right <<1|1
34 private:
35 int64 val1[N<<
2],val2[N<<
2];
36 public:
37 void modify(
const int &p,
const int &b,
const int &e,
const int &l,
const int &r,
const int &x,
const int64 &
y) {
38 if(b==l&&e==
r) {
39 val1[p]+=
x;
40 val2[p]+=
y;
41 return;
42 }
43 const int mid=(b+e)>>
1;
44 if(l<=
mid) modify(p _left,b,mid,l,std::min(mid,r),x,y);
45 if(r>mid) modify(p _right,mid+
1,e,std::max(mid+
1,l),r,x,y);
46 }
47 int64 query(
const int &p,
const int &b,
const int &e,
const int &
x) {
48 int64 ret=val1[p]*dep[x]+
val2[p];
49 if(b==e)
return ret;
50 const int mid=(b+e)>>
1;
51 if(dfn[x]<=mid) ret+=
query(p _left,b,mid,x);
52 if(dfn[x]>mid) ret+=query(p _right,mid+
1,e,x);
53 return ret;
54 }
55 #undef _left
56 #undef _right
57 };
58 SegmentTree t;
59 int main() {
60 const int n=getint(),m=
getint();
61 for(register
int i=
1;i<=n;i++
) {
62 w[i]=
getint();
63 }
64 for(register
int i=
1;i<n;i++
) {
65 add_edge(getint(),getint());
66 }
67 dfs(
1,
0);
68 for(register
int i=
1;i<=n;i++
) {
69 t.modify(
1,
1,n,dfn[i],dfn[i]+size[i]-
1,
0,w[i]);
70 }
71 for(register
int i=
0;i<m;i++
) {
72 const int op=
getint();
73 if(op==
1) {
74 const int x=getint(),a=
getint();
75 t.modify(
1,
1,n,dfn[x],dfn[x]+size[x]-
1,
0,a);
76 }
77 if(op==
2) {
78 const int x=getint(),a=
getint();
79 t.modify(
1,
1,n,dfn[x],dfn[x]+size[x]-
1,a,a-(int64)dep[x]*
a);
80 }
81 if(op==
3) {
82 const int x=
getint();
83 printf(
"%lld\n",t.query(
1,
1,n,x));
84 }
85 }
86 return 0;
87 }
View Code 同樣還是一種將樹“壓扁”的方法。
考慮我們之前講過的括號序列。
操作3中的詢問相當于前綴和。?
按照括號序列建線段樹,操作1就變成了單點修改,操作2就變成了區間+a/-a。
1 #include<cstdio>
2 #include<cctype>
3 #include<vector>
4 typedef
long long int64;
5 inline
int getint() {
6 register
char ch;
7 register
bool neg=
false;
8 while(!isdigit(ch=getchar()))
if(ch==
'-') neg=
true;
9 register
int x=ch^
'0';
10 while(isdigit(ch=getchar())) x=(((x<<
2)+x)<<
1)+(ch^
'0');
11 return neg?-
x:x;
12 }
13 const int N=
100001;
14 int w[N],dfn[N],size[N],dep[N];
15 std::vector<
int>
e[N];
16 inline
void add_edge(
const int &u,
const int &
v) {
17 e[u].push_back(v);
18 e[v].push_back(u);
19 }
20 void dfs(
const int &x,
const int &
par) {
21 size[x]=
1;
22 dfn[x]=++dfn[
0];
23 dep[x]=dep[par]+
1;
24 for(unsigned i=
0;i<e[x].size();i++
) {
25 const int &y=
e[x][i];
26 if(y==par)
continue;
27 dfs(y,x);
28 size[x]+=
size[y];
29 }
30 }
31 class SegmentTree {
32 #define _left <<1
33 #define _right <<1|1
34 private:
35 int64 val1[N<<
2],val2[N<<
2];
36 public:
37 void modify(
const int &p,
const int &b,
const int &e,
const int &l,
const int &r,
const int &x,
const int64 &
y) {
38 if(b==l&&e==
r) {
39 val1[p]+=
x;
40 val2[p]+=
y;
41 return;
42 }
43 const int mid=(b+e)>>
1;
44 if(l<=
mid) modify(p _left,b,mid,l,std::min(mid,r),x,y);
45 if(r>mid) modify(p _right,mid+
1,e,std::max(mid+
1,l),r,x,y);
46 }
47 int64 query(
const int &p,
const int &b,
const int &e,
const int &
x) {
48 int64 ret=val1[p]*dep[x]+
val2[p];
49 if(b==e)
return ret;
50 const int mid=(b+e)>>
1;
51 if(dfn[x]<=mid) ret+=
query(p _left,b,mid,x);
52 if(dfn[x]>mid) ret+=query(p _right,mid+
1,e,x);
53 return ret;
54 }
55 #undef _left
56 #undef _right
57 };
58 SegmentTree t;
59 int main() {
60 //freopen("221/haoi2015_t21.in","r+",stdin);
61 const int n=getint(),m=
getint();
62 for(register
int i=
1;i<=n;i++
) {
63 w[i]=
getint();
64 }
65 for(register
int i=
1;i<n;i++
) {
66 add_edge(getint(),getint());
67 }
68 dfs(
1,
0);
69 for(register
int i=
1;i<=n;i++
) {
70 t.modify(
1,
1,n,dfn[i],dfn[i]+size[i]-
1,
0,w[i]);
71 }
72 for(register
int i=
0;i<m;i++
) {
73 const int op=
getint();
74 if(op==
1) {
75 const int x=getint(),a=
getint();
76 t.modify(
1,
1,n,dfn[x],dfn[x]+size[x]-
1,
0,a);
77 }
78 if(op==
2) {
79 const int x=getint(),a=
getint();
80 t.modify(
1,
1,n,dfn[x],dfn[x]+size[x]-
1,a,a-(int64)dep[x]*
a);
81 }
82 if(op==
3) {
83 const int x=
getint();
84 printf(
"%lld\n",t.query(
1,
1,n,x));
85 }
86 }
87 return 0;
88 }
View Code ?
轉載于:https://www.cnblogs.com/skylee03/p/8066974.html
總結
以上是生活随笔為你收集整理的[HAOI2015]树上操作的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。