bzoj3514 Codechef MARCH14 GERALD07加强版

OI 数据结构
文章目录

ref
这题好神啊……主要要有一个思想,强制在线,又是区间,想着用主席树,搞出一个能代表每个边的东西来。我反正想不到>_<。

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
#include <iostream>
#include <cstdio>
using namespace std;
int n, m, k, T, uu, vv, zxz[400005], a[200005], ch[400005][2];
int fa[400005], rot[200005], tot, rev[400005];
struct Node{
int l, r, sum;
}nd[7200005];
void upd(int x){
if(x<=n) zxz[x] = n + m + 1;
else zxz[x] = x;
if(zxz[ch[x][0]]<zxz[x]) zxz[x] = zxz[ch[x][0]];
if(zxz[ch[x][1]]<zxz[x]) zxz[x] = zxz[ch[x][1]];
}
int getW(int x){
return ch[fa[x]][1]==x;
}
bool isRoot(int x){
return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
}
void rotate(int x){
int old=fa[x], oldf=fa[old], w=getW(x);
if(!isRoot(old)) ch[oldf][ch[oldf][1]==old] = x;
ch[old][w] = ch[x][w^1]; ch[x][w^1] = old;
fa[ch[x][w^1]] = x; fa[ch[old][w]] = old; fa[x] = oldf;
upd(old); upd(x);
}
void pushDown(int x){
if(rev[x]){
swap(ch[x][0], ch[x][1]);
rev[ch[x][0]] ^= 1;
rev[ch[x][1]] ^= 1;
rev[x] = false;
}
}
void xf(int x){
if(fa[x]) xf(fa[x]);
pushDown(x);
}
void splay(int x){
xf(x);
while(!isRoot(x)){
int f=fa[x];
if(!isRoot(f)) rotate(getW(f)==getW(x)?f:x);
rotate(x);
}
upd(x);
}
void access(int x){
int y=0;
while(x){
splay(x);
ch[x][1] = y;
upd(x);
y = x;
x = fa[x];
}
}
int findRoot(int x){
access(x);
splay(x);
while(ch[x][0])
x = ch[x][0];
splay(x);
return x;
}
void makeRoot(int x){
access(x);
splay(x);
rev[x] ^= 1;
}
void split(int x, int y){
makeRoot(x);
access(y);
splay(y);
}
void cut(int x, int y){
split(x, y);
fa[x] = ch[y][0] = 0;
}
void link(int x, int y){
makeRoot(x);
fa[x] = y;
}
int update(int pre, int l, int r, int x){
int now=++tot;
nd[now] = nd[pre];
nd[now].sum++;
int mid=(l+r)>>1;
if(l==r) ;
else{
if(x<=mid) nd[now].l = update(nd[pre].l, l, mid, x);
else nd[now].r = update(nd[pre].r, mid+1, r, x);
}
return now;
}
int query(int now, int pre, int l, int r, int x, int y){
if(l>=x && r<=y) return nd[now].sum-nd[pre].sum;
else{
int mid=(l+r)>>1;
int re=0;
if(x<=mid) re += query(nd[now].l, nd[pre].l, l, mid, x, y);
if(mid<y) re += query(nd[now].r, nd[pre].r, mid+1, r, x, y);
return re;
}
}
int main(){
cin>>n>>m>>k>>T;
for(int i=0; i<=n; i++)
zxz[i] = n + m + 1;
for(int i=1; i<=m; i++)
zxz[i+n] = i + n;
for(int i=1; i<=m; i++){
scanf("%d %d", &uu, &vv);
if(uu>vv) swap(uu, vv);
if(findRoot(uu)!=findRoot(vv)){
a[i] = 0;
link(uu, i+n);
link(vv, i+n);
}
else if(uu==vv) a[i] = m;
else{
split(uu, vv);
int tmp=zxz[vv];
if(tmp<i+n){
cut(uu, tmp);
cut(vv, tmp);
link(uu, i+n);
link(vv, i+n);
}
a[i] = tmp - n;
}
}
for(int i=1; i<=m; i++)
rot[i] = update(rot[i-1], 0, m, a[i]);
int ans=0;
for(int i=1; i<=k; i++){
scanf("%d %d", &uu, &vv);
if(T) uu ^= ans, vv ^= ans;
ans = n - query(rot[vv], rot[uu-1], 0, m, 0, uu-1);
printf("%d\n", ans);
}
return 0;
}