LCT 做法……有点长(调试输出没删)
#include <bits/stdc++.h>
using namespace std;
inline void train() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
}
inline int maxi(int a, int b) {
return a > b ? a : b;
}
inline int mini(int a, int b) {
return a < b ? a : b;
}
constexpr int N = 800004, LN = 800004*4, M = 1e6+4;
/////////////////////////////////////////////////////////////////////
// Link-Cut-Tree Template
/////////////////////////////////////////////////////////////////////
namespace LCT {
#define lc t[x].ch[0]
#define rc t[x].ch[1]
struct node {
int fa,ch[3],sum,val,lazy;
} t[LN];
bool isroot(const int& x) {
long long g=t[x].fa;
return t[g].ch[0]!=x&&t[g].ch[1]!=x;
}
void pushup(const int& x) {
t[x].sum=t[x].val^t[lc].sum^t[rc].sum;
}
void reverse(const int& x) {
if(!x)return;
swap(lc,rc);
t[x].lazy^=1;
}
void pushdown(const int& x) {
if(t[x].lazy) {
reverse(lc);
reverse(rc);
t[x].lazy=0;
}
}
void push(const int& x) {
if(!isroot(x))push(t[x].fa);
pushdown(x);
}
void rotate(const int& x) {
const int y=t[x].fa;
const int z=t[y].fa;
const int k=t[y].ch[1]==x;
if(!isroot(y)) t[z].ch[t[z].ch[1]==y]=x;
t[x].fa=z;
t[y].ch[k]=t[x].ch[k^1];
if(t[x].ch[k^1])t[t[x].ch[k^1]].fa=y;
t[y].fa=x;
t[x].ch[k^1]=y;
pushup(y);
}
void splay(const int& x) {
int y,z;
push(x);
while(!isroot(x)) {
y=t[x].fa,z=t[y].fa;
if(!isroot(y))
(t[z].ch[0]==y)^(t[y].ch[0]==x)?rotate(x):rotate(y);
rotate(x);
}
pushup(x);
}
void access(int x) {
for(int y=0; x; y=x,x=t[x].fa) {
splay(x);
rc=y;
pushup(x);
}
}
void makeroot(const int& x) {
access(x);
splay(x);
reverse(x);
}
void split(const int& x, const int& y) {
makeroot(x);
access(y);
splay(y);
}
int findroot(int x) {
access(x),splay(x);
while(lc)pushdown(x),x=lc;
pushdown(x);
return x;
}
void link(const int& x,const int& y) {
int fx = findroot(x), fy = findroot(y);
if (fx == fy) return;
makeroot(x);
t[x].fa=y;
}
void cut(const int& x,const int& y) {
makeroot(x);
access(y);
splay(y);
if(t[y].ch[0]!=x||rc)return;
t[x].fa=t[y].ch[0]=0;
pushup(x);
}
int Lca(int x, int y) {
int p = 0;
makeroot(findroot(x));
access(y);
for (; x; p = x, x = t[x].fa)
splay(x), rc = p;
return p;
}
#define Findroot findroot
#define Link link
};
/////////////////////////////////////////////////////////////////////
// End of Link-Cut-Tree Template
/////////////////////////////////////////////////////////////////////
struct edge {
int to, id;
edge() {
}
edge(int to) : to(to) {
}
edge(int to, int id) : to(to), id(id) {
}
};
struct op {
int type, u, v;
};
op data[M];
vector<edge> graph[N], gentree[N];
int n, m, q, tid, father[N], ax[M], bx[M], save[M], depth[N], enable_when[N], target[N];
bool ans[N];
bool vis[N];
struct dset {
dset() {
}
int fa[N], sz[N];
inline void init(const int& n) {
for (int i = 1; i <= n; i++) {
fa[i] = i;
sz[i] = 1;
}
}
int query(const int& x) {
return x == fa[x] ? x : fa[x] = query(fa[x]);
}
inline void merge(const int& a, const int& b) {
int qa = query(a), qb = query(b);
if (qa == qb) return;
if (sz[qa] < sz[qb]) swap(qa, qb);
fa[qb] = qa;
sz[qa] += sz[qb];
}
};
dset tarjan, complete, gens;
bool cmp(const edge &a, const edge &b) {
return save[a.id] > save[b.id];
}
int src, ct, lctlca = -1;
int fillup(int l, int r) {
// cerr << "fillup(" << l << "," << r << "," << "), depth: " << depth[l] << "," << depth[r] << ", timeout: " << enable_when[l] << "," << enable_when[r] << "\n";
if (depth[l] < depth[lctlca]) l = lctlca;
if (depth[r] < depth[lctlca]) r = lctlca;
if (l != r && (enable_when[l] >= ct || enable_when[r] >= ct)) {
if (depth[l] < depth[r]) swap(l, r);
if (enable_when[l] < ct) swap(l, r);
int ft = father[target[l]];
tarjan.merge(l, src);
return target[l] = fillup(ft, r);
} else {
tarjan.merge(l, src);
tarjan.merge(r, src);
return l;
}
}
inline void edge_worker(int ap, int bp, const int& i) {
// Skip tree edge.
if (father[ap] == bp || father[bp] == ap) {
if ((father[ap] == bp && enable_when[ap] == i) || (father[bp] == ap && enable_when[bp] == i)) {
if (father[bp] == ap) swap(ap, bp);
// bp is the father of ap then
LCT::Link(ap, bp);
return;
}
}
// cerr << "start fillup" << endl;
// Can't ensure correctness. has guaranteed that it is not tree-edge.
src = ap; ct = i; lctlca = LCT::Lca(ap, bp);
fillup(ap, bp);
// cerr << endl;
}
priority_queue<edge> pq;
bool operator < (const edge &a, const edge &b) {
return a.id < b.id;
}
void dfs1(int cur, int fa) {
vis[cur] = true;
for (auto &i : graph[cur]) {
pq.push(edge(i.id, save[i.id]));
if (vis[i.to]) continue;
dfs1(i.to, cur);
}
}
// Scan "enable-when" requirements.
void dfs3(int cur, int fa) {
// cerr << "tree construction " << fa << " -> " << cur << ", enabled at " << enable_when[cur] << endl;
father[cur] = fa;
depth[cur] = depth[fa] + 1;
for (auto &i : gentree[cur]) {
if (i.to == fa) continue;
enable_when[i.to] = save[i.id];
if (save[i.id] > q) LCT::Link(i.to, cur); // cur is father or i
dfs3(i.to, cur);
}
}
map<pair<int, int>, int> ids;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x<0)
putchar('-'),x=-x;
if(x>9)
write(x/10);
putchar(x%10+'0');
return;
}
int main() {
// cin>>n>>m>>q;
n = read(); m = read(); q = read();
tarjan.init(n); complete.init(n); gens.init(n);
for (int i = 1; i <= m; i++) {
// cin>>ax[i]>>bx[i];
ax[i] = read(); bx[i] = read();
graph[ax[i]].push_back(edge(bx[i], i));
graph[bx[i]].push_back(edge(ax[i], i));
ids[make_pair(mini(ax[i], bx[i]), maxi(ax[i], bx[i]))] = i;
save[i] = q+1;
complete.merge(ax[i], bx[i]);
}
for (int i = 1; i <= q; i++) {
// cin>>data[i].type;
char ch;
do {
ch = getchar();
} while (ch != 'Z' && ch != 'P');
// cin>>ch;
data[i].type = (ch == 'Z' ? 1 : 2);
// cin>>data[i].u>>data[i].v;
data[i].u = read(); data[i].v = read();
if (data[i].type == 1) {
auto ap = make_pair(mini(data[i].u, data[i].v), maxi(data[i].u, data[i].v));
save[ids[ap]] = i;
}
}
for (int i = 1; i <= n; i++) {
if (complete.query(i) == i) {
// Generate a tree:
dfs1(i, i);
// cerr << "Construct tree for " << i << endl;
int cnt = 0;
while ((cnt <= complete.sz[i]) && (!pq.empty())) {
edge pt = pq.top();
pq.pop();
if (gens.query(ax[pt.to]) == gens.query(bx[pt.to])) continue;
gentree[ax[pt.to]].emplace_back(edge(bx[pt.to], pt.to));
gentree[bx[pt.to]].emplace_back(edge(ax[pt.to], pt.to));
cnt++;
// cerr << "connected " << ax[pt.to] << " -> " << bx[pt.to] << " with time " << save[pt.to] << endl;
gens.merge(ax[pt.to], bx[pt.to]);
}
while (!pq.empty()) pq.pop();
dfs3(i, i);
}
target[i] = i;
}
for (int i = 1; i <= n; i++) {
// cerr << "enable time for " << i << " is " << enable_when[i] << endl;
for (auto &j : graph[i]) {
if (save[j.id] > q) edge_worker(i, j.to, q+1);
}
}
for (int i = q; i >= 1; i--) {
// cerr << "==============================\n";
if (data[i].type ^ 1) {
ans[i] = (tarjan.query(data[i].u) == tarjan.query(data[i].v) ? true : false);
} else {
// Query through
// int ap = ax[data[i].u], bp = bx[data[i].u];
int ap = data[i].u, bp = data[i].v;
edge_worker(ap, bp, i);
}
}
for (int i = 1; i <= q; i++) {
if (data[i].type == 1) continue;
// cout << (ans[i] ? "TAK\n" : "NIE\n");
if (ans[i]) puts("TAK");
else puts("NIE");
}
return 0;
}