AT_abc350_g [ABC350G] Mediator

思路

有加边操作,一眼 LCT。问题在于处理询问操作。

首先,判断联通。如果 x,yx,y 不在同一个联通块内,则一定没有答案。

其次,求出 x,yx,y 之间节点的数量 numnum(包括 x,yx,y)。如果 num=3num = 3 说明 x,yx,y 之间有一个共同的节点;如果 num=2num = 2 说明 x,yx,y 直接连接;如果 num>3num > 3 说明 x,yx,y 之间有不止一个节点。

num=3num = 3 时,考虑如何计算该节点的编号。维护节点的编和,查询 x,yx,y 之间的编号和 sumsum,答案显然就是 sumxysum - x - y

全都是 LCT 基本操作,难点在于会不会 LCT。

Code

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 <bits/stdc++.h>
#define fst first
#define snd second
#define re register
#define int long long

using namespace std;

typedef pair<int,int> pii;
const int N = 1e5 + 10,mod = 998244353;
int n,q,lst,f[N];

inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}

struct LCT{
#define fp(u) (tr[u].fa)
#define son(u,k) (tr[u].ch[k])
#define getch(u) (u == son(fp(u),1))
#define isroot(u) (u != son(fp(u),getch(u)))

struct node{
int fa,ch[2];
pii val,sum;
int tag;
}tr[N];

inline void calc(int u){
if (!u) return;
tr[u].tag ^= 1;
swap(son(u,0),son(u,1));
}

inline void maintain(int u,int fa,int k,bool falg){
if (!falg || !isroot(fp(u))) son(fa,k) = u;
fp(u) = fa;
}

inline void pushup(int u){
tr[u].sum.fst = tr[son(u,0)].sum.fst + tr[son(u,1)].sum.fst + tr[u].val.fst;
tr[u].sum.snd = tr[son(u,0)].sum.snd + tr[son(u,1)].sum.snd + tr[u].val.snd;
}

inline void pushdown(int u){
if (tr[u].tag){
calc(son(u,0)); calc(son(u,1));
tr[u].tag = 0;
}
}

inline void update(int u){
if (!isroot(u)) update(fp(u));
pushdown(u);
}

inline void rotate(int u){
int fa = fp(u);
int ffa = fp(fa);
int k = getch(u);
maintain(son(u,k ^ 1),fa,k,false);
maintain(u,ffa,getch(fa),true);
maintain(fa,u,k ^ 1,false);
pushup(fa);
}

inline void splay(int u){
update(u);
while (!isroot(u)){
int fa = fp(u);
if (!isroot(fa)){
if (getch(u) != getch(fa)) rotate(u);
else rotate(fa);
}
rotate(u);
}
pushup(u);
}

inline void access(int u){
int p = 0;
while (u){
splay(u);
son(u,1) = p; pushup(u);
p = u; u = fp(u);
}
}

inline void makeroot(int u){
access(u); splay(u);
calc(u);
}

inline int split(int x,int y){
makeroot(x);
access(y); splay(y);
return y;
}

inline int find(int u){
access(u); splay(u);
pushdown(u);
while (son(u,0)) pushdown(u = son(u,0));
splay(u);
return u;
}

inline void link(int x,int y){
makeroot(x);
if (find(y) != x) fp(x) = y;
}

#undef fp
#undef son
#undef getch
#undef isroot
}T;

inline int find(int x){
if (f[x] != x) return f[x] = find(f[x]);
return f[x];
}

inline void merge(int a,int b){
int x = find(a),y = find(b);
if (x == y) return;
f[x] = y;
}

signed main(){
n = read(),q = read();
for (re int i = 1;i <= n;i++){
T.tr[i].val = {i,1};
f[i] = i;
}
while (q--){
int op,x,y;
op = (read() * (1 + lst) % mod) % 2 + 1;
x = (read() * (1 + lst) % mod) % n + 1;
y = (read() * (1 + lst) % mod) % n + 1;
if (op == 1){
T.link(x,y); merge(x,y);
}
else{
if (find(x) != find(y)) printf("%lld\n",lst = 0);
else{
pii ans = T.tr[T.split(x,y)].sum;
if (ans.snd != 3) printf("%lld\n",lst = 0);
else printf("%lld\n",lst = (ans.fst - x - y));
}
}
}
return 0;
}

AT_abc350_g [ABC350G] Mediator
http://watersun.top/[题解]AT_abc350_g [ABC350G] Mediator/
作者
WaterSun
发布于
2024年4月21日
许可协议