「广州集训 Day1」小豪的花园 - 线段树 | Bill Yang's Blog

「广州集训 Day1」小豪的花园 - 线段树

题目大意

小豪有一个花园,里面有n个花棚,编号1..n,每个花棚里有一定数量的花a i 。小豪花园的路十分神奇,可以使得任意两个花棚之间仅有一条最短路,即形成树结构,其中根节点是1号花棚。现在小豪打算修缮一下他的花园,重新分配每个花棚里花的数量。为了能方便快捷地知道花园的情况,小豪现在需要你的帮助。具体地说,小豪共有m个操作。操作有三种:

  1. 1 u k 表示如果一个花棚在以u号花棚为根的子树中,那么小豪会把这个花棚花的数量模k
  2. 2 u x 表示小豪将u号花棚花的数量变成x
  3. 3 u v 表示小豪询问从u号花棚走到v号花棚总共能看到的花的数量

你能帮助小豪吗?


题目分析

又是这道众人皆知的结论题,不过套了个树剖,一点新意也没有。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
const int maxn=100005;
struct Tree {
int left,right;
LL max,sum;
Tree(int l=0,int r=0,LL m=0,LL s=0):left(l),right(r),max(m),sum(s) {}
};
struct Segment_Tree {
Tree tree[maxn*4];
#define ls index<<1
#define rs index<<1|1
void build(int index,int Left,int Right) {
tree[index]=Tree(Left,Right);
if(Left==Right)return;
int mid=(Left+Right)>>1;
build(ls,Left,mid);
build(rs,mid+1,Right);
push_up(index);
}
void push_up(int index) {
tree[index].max=max(tree[ls].max,tree[rs].max);
tree[index].sum=tree[ls].sum+tree[rs].sum;
}
void modify(int index,int target,LL val) {
if(tree[index].left>target||tree[index].right<target)return;
if(tree[index].left==tree[index].right) {
tree[index].max=tree[index].sum=val;
return;
}
modify(ls,target,val);
modify(rs,target,val);
push_up(index);
}
void mod(int index,int Left,int Right,LL val) {
if(tree[index].left>Right||tree[index].right<Left)return;
if(tree[index].left==tree[index].right) {
tree[index].max%=val;
tree[index].sum%=val;
return;
}
if(tree[index].max<val)return;
mod(ls,Left,Right,val);
mod(rs,Left,Right,val);
push_up(index);
}
LL query(int index,int Left,int Right) {
if(tree[index].left>Right||tree[index].right<Left)return 0;
if(Left<=tree[index].left&&Right>=tree[index].right)return tree[index].sum;
return query(ls,Left,Right)+query(rs,Left,Right);
}
} st;
vector<int>edges[maxn];
int father[maxn],Depth[maxn],Size[maxn],Top[maxn],Son[maxn],M[maxn],cnt=0;
void AddEdge(int x,int y) {
edges[x].push_back(y);
}
void Dfs1(int Now,int fa,int depth) {
father[Now]=fa;
Depth[Now]=depth;
Size[Now]=1;
for(int& Next:edges[Now]) {
if(Next==fa)continue;
Dfs1(Next,Now,depth+1);
Size[Now]+=Size[Next];
if(Size[Next]>Size[Son[Now]])Son[Now]=Next;
}
}
void Dfs2(int Now,int top) {
Top[Now]=top;
M[Now]=++cnt;
if(Son[Now])Dfs2(Son[Now],top);
for(int& Next:edges[Now]) {
if(Next==Son[Now]||Next==father[Now])continue;
Dfs2(Next,Next);
}
}
int n,m,a[maxn];
void build() {
Dfs1(1,0,1);
Dfs2(1,1);
st.build(1,1,cnt);
for(int i=1; i<=n; i++)st.modify(1,M[i],a[i]);
}
void modify(int index,int v) {
st.modify(1,M[index],v);
}
LL query(int from,int to) {
int t1=Top[from],t2=Top[to];
LL sum=0;
while(t1!=t2) { //爬树
if(Depth[t1]<Depth[t2]) {
swap(t1,t2);
swap(from,to);
}
sum+=st.query(1,M[t1],M[from]);
from=father[t1];
t1=Top[from];
}
if(Depth[from]>Depth[to])swap(from,to);
sum+=st.query(1,M[from],M[to]);
return sum;
}
int main() {
n=Get_Int();
m=Get_Int();
for(int i=1; i<n; i++) {
int x=Get_Int(),y=Get_Int();
AddEdge(x,y);
AddEdge(y,x);
}
for(int i=1; i<=n; i++)a[i]=Get_Int();
build();
for(int i=1; i<=m; i++) {
int opt=Get_Int(),x=Get_Int(),y=Get_Int();
if(opt==1)st.mod(1,M[x],M[x]+Size[x]-1,y);
else if(opt==2)modify(x,y);
else printf("%lld\n",query(x,y));
}
return 0;
}
姥爷们赏瓶冰阔落吧~
0%