【主席树启发式合并】【P3302】[SDOI2013]森林

Limitation

$1~\leq~n,~Q~\leq~80000$

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif

typedef long long int ll;

namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
}

template <typename T>
inline void qr(T &x) {
char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
}

namespace OPT {
char buf[120];
}

template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
int top=0;
do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
}

const int maxn = 80005;

int lstans, n, m, t;
int ufs[maxn], sz[maxn], MU[maxn], tmp[maxn], anc[18][maxn], depth[maxn];
bool vis[maxn];

struct Tree {
Tree *ls, *rs;
int l, r, v;

~Tree() {
if (this->ls) {
delete this->ls;
delete this->rs;
}
}

Tree() : ls(NULL), rs(NULL), l(0), r(0), v(0) {}
};
Tree *rot[maxn];

struct Edge {
int v;
Edge *nxt;

Edge(const int _v, Edge *h) : v(_v), nxt(h) {}
};
Edge *hd[maxn];
void cont(const int u, const int v) {
hd[u] = new Edge(v, hd[u]);
hd[v] = new Edge(u, hd[v]);
}

void init_hash();
int find(const int x);
int GetLCA(int u, int v);
void dfs(const int u, const int rt);
void build(Tree *u, Tree *pre, const int v);
void buildzero(Tree *u, const int l, const int r);
int query(const Tree *const u, const Tree *const v, const Tree *const x, const Tree *const y, const int k);

int main() {
freopen("1.in", "r", stdin);
qr(lstans); lstans = 0;
qr(n); qr(m); qr(t);
for (int i = 1; i <= n; ++i) {
qr(MU[i]);
}
init_hash();
buildzero(rot[0] = new Tree, 1, n);
for (int i = 1, u, v; i <= m; ++i) {
u = v = 0; qr(u); qr(v);
cont(u, v);
}
for (int i = 1; i <= n; ++i) if (!vis[i]) {
dfs(i, i);
}
int a, b, c;
while (t--) {
char op;
do op = IPT::GetChar(); while ((op != 'Q') && (op != 'L'));
if (op == 'Q') {
a = b = c = 0; qr(a); qr(b); qr(c);
a ^= lstans; b ^= lstans; c ^= lstans;
int k = GetLCA(a, b);
qw(lstans = tmp[query(rot[a], rot[b], rot[k], rot[anc[0][k]], c)], '\n', true);
} else {
a = b = 0; qr(a); qr(b);
a ^= lstans; b ^= lstans;
int fa = find(a), fb = find(b);
if (sz[fa] > sz[fb]) {
std::swap(a, b);
std::swap(fa, fb);
}
sz[fb] += sz[fa];
anc[0][a] = b;
dfs(a, fb);
cont(a, b);
}
}
return 0;
}

void dfs(const int u, const int rt) {
vis[u] = true;
sz[u] = 1; ufs[u] = rt;
depth[u] = depth[anc[0][u]] + 1;
build(rot[u] = new Tree, rot[anc[0][u]], MU[u]);
for (int i = 0; i < 17; ++i) {
anc[i + 1][u] = anc[i][anc[i][u]];
}
for (auto e = hd[u]; e; e = e->nxt) if (e->v != anc[0][u]) {
anc[0][e->v] = u;
dfs(e->v, rt);
sz[u] += sz[e->v];
}
}

void init_hash() {
memcpy(tmp + 1, MU + 1, n << 2);
std::sort(tmp + 1, tmp + 1 + n);
auto ed = std::unique(tmp + 1, tmp + 1 + n);
for (int i = 1; i <= n; ++i) {
MU[i] = std::lower_bound(tmp + 1, ed, MU[i]) - tmp;
}
}

void buildzero(Tree *u, const int l, const int r) {
if ((u->l = l) == (u->r = r)) return;
int mid = (l + r) >> 1;
buildzero(u->ls = new Tree, l, mid); buildzero(u->rs = new Tree, mid + 1, r);
}

void build(Tree *u, Tree *pre, const int v) {
*u = *pre; ++u->v;
if (u->l == u->r) return;
if (u->ls->r >= v) {
build(u->ls = new Tree, pre->ls, v);
} else {
build(u->rs = new Tree, pre->rs, v);
}
}

int GetLCA(int u, int v) {
if (depth[u] > depth[v]) {
std::swap(u, v);
}
int delta = depth[v] - depth[u];
for (int i = 17; delta; --i) if (delta >= (1 << i)) {
delta -= 1 << i;
v = anc[i][v];
}
if (u == v) return u;
for (int i = 17; ~i; --i) if (anc[i][u] != anc[i][v]) {
u = anc[i][u]; v = anc[i][v];
}
return anc[0][v];
}

int query(const Tree *const u, const Tree *const v, const Tree *const x, const Tree *const y, const int k) {
if (u->l == u->r) return u->l;
int lv = u->ls->v + v->ls->v - x->ls->v - y->ls->v;
if (lv >= k) {
return query(u->ls, v->ls, x->ls, y->ls, k);
} else {
return query(u->rs, v->rs, x->rs, y->rs, k - lv);
}
}

inline int find(const int x) {
return ufs[x] == x ? x : ufs[x];
}



Summary

posted @ 2019-06-30 02:00  一扶苏一  阅读(219)  评论(0编辑  收藏  举报