隐藏
「bzoj2959」长跑 - LCT+并查集 | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「bzoj2959」长跑 - LCT+并查集

题目大意

    给一个图,要求支持添加一条边,修改点权,询问一个点出发到另一个点路径上点权的最大和(路径上每个点权仅计算一次)。


题目分析

考虑若没有添加边操作怎么做。
因为每个点权仅计算一次,故可以对边双连通分量缩点。
然后用树链剖分维护缩完点后的树。

由于有加边操作,因此不能使用树链剖分,考虑使用动态树。
每次加边考虑是否形成环,若形成环将其缩成一个点,维护路径和。

因为涉及到缩点操作,不妨使用并查集来维护缩点的代表结点。
在本处我使用了两个并查集,$Together$用于判断是否连通,$Belong$用于维护代表结点。
其实$Together$是没有必要维护的,因为在$Belong$的辅助下,LCT可以完成连通性判断,但因为常数大,故改用并查集。


代码

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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<climits>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;

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=150005;

struct Union_Set {
int father[maxn];
void init(int n) {
for(int i=1; i<=n; i++)father[i]=i;
}
int Get_Father(int x) {
if(father[x]==x)return x;
else return father[x]=Get_Father(father[x]);
}
void merge(int x,int y) {
father[Get_Father(x)]=Get_Father(y);
}
bool check(int x,int y) {
return Get_Father(x)==Get_Father(y);
}
} Together,Belong;

struct Link_Cut_Tree {
struct Tree {
int father,child[2];
bool rev;
int sum,val;
} tree[maxn];
stack<int>S;
#define fa(x) tree[x].father
#define ls(x) tree[x].child[0]
#define rs(x) tree[x].child[1]
#define rev(x) tree[x].rev
bool isroot(int index) {
return ls(Belong.Get_Father(fa(index)))!=index&&rs(Belong.Get_Father(fa(index)))!=index;
}
bool checkson(int index) {
return rs(Belong.Get_Father(fa(index)))==index;
}
void push_down(int index) {
if(!rev(index))return;
swap(ls(index),rs(index));
rev(ls(index))^=1;
rev(rs(index))^=1;
rev(index)=0;
}
void push_up(int index) {
tree[index].sum=tree[ls(index)].sum+tree[rs(index)].sum+tree[index].val;
}
void rotate(int index) {
int father=Belong.Get_Father(fa(index)),grand=Belong.Get_Father(fa(father)),side=checkson(index);
if(!isroot(father))tree[grand].child[checkson(father)]=index;
tree[father].child[side]=tree[index].child[side^1];
fa(tree[father].child[side])=father;
fa(father)=index;
tree[index].child[side^1]=father;
fa(index)=grand;
push_up(father);
push_up(index);
}
void splay(int index) {
S.push(index);
for(int i=index; !isroot(i); i=Belong.father[fa(i)])S.push(Belong.father[fa(i)]);
while(!S.empty())push_down(S.top()),S.pop();
for(int father; !isroot(index); rotate(index)) {
father=Belong.Get_Father(fa(index));
if(!isroot(father))rotate(checkson(index)==checkson(father)?father:index);
}
}
void access(int index) {
for(int son=0; index; son=index,index=Belong.Get_Father(fa(index))) {
splay(index);
rs(index)=son;
push_up(index);
}
}
void reverse(int index) {
access(index);
splay(index);
rev(index)^=1;
}
void link(int x,int y) {
reverse(x);
fa(x)=y;
}
void split(int x,int y) {
reverse(x);
access(y);
splay(y);
}
void rebuild(int x,int y) {
split(x,y);
queue<int>Q;
Q.push(y);
while(!Q.empty()) {
int Now=Q.front();
Q.pop();
Belong.father[Now]=y;
if(ls(Now))Q.push(ls(Now));
if(rs(Now))Q.push(rs(Now));
ls(Now)=rs(Now)=0;
}
tree[y].val=tree[y].sum;
}
} lct;

int n,m,val[maxn];

int main() {
n=Get_Int();
m=Get_Int();
Together.init(n),Belong.init(n);
for(int i=1; i<=n; i++)val[i]=lct.tree[i].val=Get_Int();
for(int i=1; i<=m; i++) {
int opt=Get_Int(),x=Get_Int(),y=Get_Int();
if(opt==1) {
x=Belong.Get_Father(x),y=Belong.Get_Father(y);
if(x==y)continue;
if(!Together.check(x,y))lct.link(x,y),Together.merge(x,y);
else lct.rebuild(x,y);
} else if(opt==2) {
int tmp=Belong.Get_Father(x);
lct.tree[tmp].val+=y-val[x];
lct.splay(tmp);
val[x]=y;
} else {
if(!Together.check(x,y)) {
puts("-1");
continue;
}
x=Belong.Get_Father(x),y=Belong.Get_Father(y);
if(x==y)printf("%d\n",lct.tree[x].val);
else {
lct.split(x,y);
printf("%d\n",lct.tree[y].sum);
}
}
}
return 0;
}
姥爷们赏瓶冰阔落吧~