「bzoj4668」冷战 - LCT/并查集 | Bill Yang's Blog

「bzoj4668」冷战 - LCT/并查集

题目大意

    Reddington是美国的海军上将。由于战争局势十分紧张,因此他需要时刻关注着苏联的各个活动,避免使自己的国家陷入困境。苏联在全球拥有$N$个军工厂,但由于规划不当,一开始这些军工厂之间是不存在铁路的,为了使武器制造更快,苏联决定修建若干条道路使得某些军工厂联通。
    Reddington得到了苏联的修建日程表,并且他需要时刻关注着某两个军工厂是否联通,以及最早在修建哪条道路时会联通。具体而言,现在总共有$M$个操作,操作分为两类:
    •$0\,\,u\,\,v$,这次操作苏联会修建一条连接$u$号军工厂及$v$号军工厂的铁路,注意铁路都是双向的;
    •$1\,\,u\,\,v$,Reddington需要知道$u$号军工厂及$v$号军工厂最早在加入第几条条铁路后会联通,假如到这次操作都没有联通,则输出$0$;
    作为美国最强科学家,Reddington需要你帮忙设计一个程序,能满足他的要求。


题目分析

历史这道题一模一样。
我就是喜欢LCT,你不服?


代码

LCT有点卡常数,用FastIO卡过。

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
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
typedef long long LL;
namespace FastIO {
const int L=1<<15;
char buf[L],*S,*T;
char getchar() {
if(S==T) {T=(S=buf)+fread(buf,1,L,stdin);if(S==T)return EOF;}
return *S++;
}
LL Get_Int() {
LL res=0,bj=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')bj=-1;c=getchar();}
while(isdigit(c)) {res=res*10+c-'0';c=getchar();}
return res*bj;
}
}
using FastIO::Get_Int;
const int maxn=500005;
struct Tree {
int father,child[2];
bool rev;
int max,val;
};
struct Link_Cut_Tree {
Tree tree[maxn*2];
stack<int>S;
Link_Cut_Tree() {
for(int i=0; i<=maxn; i++)tree[i].max=tree[i].val=-0x7fffffff/2;
}
#define ls(x) tree[x].child[0]
#define rs(x) tree[x].child[1]
#define fa(x) tree[x].father
#define rev(x) tree[x].rev
bool isroot(int index) {
return ls(fa(index))!=index&&rs(fa(index))!=index;
}
bool checkson(int index) {
return rs(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].max=max(max(tree[ls(index)].max,tree[rs(index)].max),tree[index].val);
}
void rotate(int index) {
int father=fa(index),grand=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=fa(i))S.push(fa(i));
while(!S.empty())push_down(S.top()),S.pop();
for(int father; !isroot(index); rotate(index)) {
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=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 link(int index,int x,int y,int val) {
link(x,index);
link(index,y);
tree[index].val=tree[index].max=val;
}
int get_root(int index) {
access(index);
splay(index);
int u=index;
while(ls(u))u=ls(u);
return u;
}
} lct;
int n,m,cnt,step=0,lastans=0;
int main() {
cnt=n=Get_Int();
m=Get_Int();
for(int i=1; i<=m; i++) {
int opt=Get_Int(),x=Get_Int()^lastans,y=Get_Int()^lastans;
if(opt==0) {
++step;
if(lct.get_root(x)==lct.get_root(y))continue;
lct.link(++cnt,x,y,step);
} else {
if(lct.get_root(x)!=lct.get_root(y)) {
printf("%d\n",lastans=0);
continue;
}
lct.split(x,y);
printf("%d\n",lastans=lct.tree[y].max);
}
}
return 0;
}

0%