bzoj 3514 Codechef MARCH14 GERALD07加强版 主席树+LCT
题面
解法
思路很妙
参见hzwer的题解
主席树+LCT……真是个毒瘤的组合
时间复杂度:\(O((m+q)\ log\ m)\)
代码
#include <bits/stdc++.h>
#define N 400010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Node {
int x, y;
} a[N];
struct SgementTree {
struct Node {
int lc, rc, cnt;
} t[N * 35];
int tot;
int ins(int k, int l, int r, int x) {
int ret = ++tot; t[ret] = t[k]; t[ret].cnt++;
if (l == r) return ret; int mid = (l + r) >> 1;
if (x <= mid) t[ret].lc = ins(t[k].lc, l, mid, x);
else t[ret].rc = ins(t[ret].rc, mid + 1, r, x);
return ret;
}
int query(int k1, int k2, int l, int r, int x) {
if (l == r) return t[k2].cnt - t[k1].cnt;
int mid = (l + r) >> 1;
if (x <= mid) return query(t[k1].lc, t[k2].lc, l, mid, x);
return t[t[k2].lc].cnt - t[t[k1].lc].cnt + query(t[k1].rc, t[k2].rc, mid + 1, r, x);
}
} T;
namespace LCT {
struct splay {
int fa, rev, val, mn, pathfa, child[2];
} t[N];
int son(int x, int y) {return t[x].child[1] == y;}
int mn(int x) {if (!x) return INT_MAX; return t[x].mn;}
void rev(int x) {if (!x) return; t[x].rev ^= 1;}
void update(int x) {if (!x) return; t[x].mn = min(mn(t[x].child[0]), min(mn(t[x].child[1]), t[x].val));}
void pushdown(int x) {
if (!x) return;
int k = t[x].rev;
if (k) {
rev(x), swap(t[x].child[0], t[x].child[1]);
rev(t[x].child[0]), rev(t[x].child[1]);
}
}
void Connect(int x, int y, int k) {
if (x) t[x].child[k] = y;
if (y) t[y].fa = x; update(x);
}
void Rotate(int x) {
int y = t[x].fa, z = t[y].fa;
pushdown(y), pushdown(x);
swap(t[x].pathfa, t[y].pathfa);
int a = son(y, x), b = !a;
Connect(z, x, son(z, y));
Connect(y, t[x].child[b], a);
Connect(x, y, b);
update(y), update(x);
}
void Splay(int x) {
while (t[x].fa) {
int y = t[x].fa, z = t[y].fa;
if (z) {
pushdown(z), pushdown(y);
(son(z, y) ^ son(y, x)) ? Rotate(x) : Rotate(y);
}
Rotate(x);
}
}
void expose(int x) {
Splay(x), pushdown(x);
int y = t[x].child[1];
t[y].fa = 0, t[y].pathfa = x;
t[x].child[1] = 0, update(x);
}
void access(int x) {
for (expose(x); t[x].pathfa; Splay(x)) {
expose(t[x].pathfa);
Connect(t[x].pathfa, x, 1);
t[x].pathfa = 0;
}
}
int findroot(int x) {
access(x), Splay(x);
for (pushdown(x); t[x].child[0]; x = t[x].child[0], pushdown(x));
return x;
}
void evert(int x) {access(x), Splay(x), rev(x);}
void link(int x, int y) {evert(y), t[y].pathfa = x;}
void cut(int x, int y) {
evert(x), access(y);
Splay(y), pushdown(y);
t[t[y].child[0]].fa = 0;
t[y].child[0] = 0, update(y);
}
int query(int x, int y) {
evert(x), access(y), Splay(y);
return t[y].mn;
}
}
int n, m, q, key, cur[N], rt[N];
int main() {
using namespace LCT;
read(n), read(m); read(q), read(key);
for (int i = 1; i <= n; i++) t[i].val = t[i].mn = INT_MAX;
int tot = n;
for (int i = 1; i <= m; i++) {
read(a[i].x), read(a[i].y); tot++;
if (a[i].x == a[i].y) {cur[i] = i; continue;}
if (findroot(a[i].x) == findroot(a[i].y)) {
cur[i] = query(a[i].x, a[i].y); int t = cur[i] + n;
cut(a[cur[i]].x, t), cut(t, a[cur[i]].y);
}
t[tot].val = t[tot].mn = i;
link(a[i].x, tot), link(tot, a[i].y);
}
for (int i = 1; i <= m; i++) rt[i] = T.ins(rt[i - 1], 0, m, cur[i]);
int ans = 0;
while (q--) {
int l, r; read(l), read(r);
if (key == 1) l ^= ans, r ^= ans;
ans = n - T.query(rt[l - 1], rt[r], 0, m, l - 1);
cout << ans << "\n";
}
return 0;
}