3514: Codechef MARCH14 GERALD07加强版
Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 1900 Solved: 721
[ Submit][ Status][ Discuss]
Description
N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。
Input
第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。
Output
K行每行一个整数代表该组询问的联通块个数。
Sample Input
3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2
Sample Output
2
1
3
1
1
3
1
HINT
对于100%的数据,1≤N、M、K≤200,000。
2016.2.26提高时限至60s
Source
这是一道关于LCT维护动态图的连通性问题。
先说做法:
1.先将每条边加入图中,然后如果这条边所在两个点已经构成了环,那么把这个环中最早加入的一条边,并把这条边记录为当前边的前驱。early[i]=j
2.那么对于l~r区间的每天边,我们需要的答案就是n-(∑[early[i]<l==1](l<=i<=r))也及n-(l~r中pre小于等于l的边的个数)
About正确性:如果要是early[i]<l说明这条边一定连接了两个连通块,因此这条边减少了一个连同块,对答案的贡献是-1。否则它对答案没有贡献。
维护?:对于1.可以用LCT,对于一条边记其边权是其加入时间戳。然后边权转点权,用LCT维护最小值节点即可。对于2.可以用主席树,查询区间小于某个数的个数即可。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#define maxn 440000
#define maxt 4400000
#define ls ch[p][0]
#define rs ch[p][1]
#define inf 0x3f3f3f3f
using namespace std;
int read() {
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = x * 10 - '0' + ch; ch = getchar();}
return x * f;
}
int ch[maxn][2], fa[maxn], mn[maxn], val[maxn];
bool rev[maxn];
int root[maxn], sum[maxt], lc[maxt], rc[maxt], sz;
int n, m, Q, type, top, st[maxn], early[maxn], eu[maxn], ev[maxn];
bool wh(int p) {return ch[fa[p]][1] == p;}
bool Isroot(int p) {return ch[fa[p]][0] != p && ch[fa[p]][1] != p;}
void update(int p) {
mn[p] = p;
if(val[mn[p]] > val[mn[ls]]) mn[p] = mn[ls];
if(val[mn[p]] > val[mn[rs]]) mn[p] = mn[rs];
}
void push_down(int p) {
if(rev[p]) {
rev[ls] ^= 1; rev[rs] ^= 1;
rev[p] ^= 1; swap(ls, rs);
}
}
void push_up(int p) {
st[top = 1] = p;
for(int i = p; !Isroot(i); i = fa[i]) st[++top] = fa[i];
for(int i = top; i; --i) push_down(st[i]);
}
void Rotate(int p) {
int f = fa[p], g = fa[f], c = wh(p);
if(!Isroot(f)) ch[g][wh(f)] = p; fa[p] = g;
ch[f][c] = ch[p][c ^ 1]; if(ch[f][c]) fa[ch[f][c]] = f;
ch[p][c ^ 1] = f; fa[f] = p;
update(f);
}
void Splay(int p) {
push_up(p);
for(; !Isroot(p); Rotate(p))
if(!Isroot(fa[p])) Rotate(wh(fa[p]) == wh(p) ? fa[p] : p);
update(p);
}
void Access(int p) {
for(int pre = 0; p; pre = p, p = fa[p]) {
Splay(p);
rs = pre;
update(p);
}
}
void makeroot(int p) {Access(p); Splay(p); rev[p] ^= 1;}
void Link(int p, int g) {
makeroot(p);
fa[p] = g;
}
void Cut(int p, int g) {
makeroot(p); Access(g); Splay(g);
fa[p] = ch[g][0] = 0;
}
int Query(int u, int v) {
makeroot(u); Access(v); Splay(v);
return mn[v];
}
int find(int p) {Access(p); Splay(p); while(ls) p = ls; return p;}
void add(int L, int R, int pre_p, int &cur_p, int val) {
sum[cur_p = ++sz] = sum[pre_p] + 1;
if(L == R) return;
int mid = L + R >> 1;
if(val <= mid) {
rc[cur_p] = rc[pre_p];
add(L, mid, lc[pre_p], lc[cur_p], val);
}
else {
lc[cur_p] = lc[pre_p];
add(mid + 1, R, rc[pre_p], rc[cur_p], val);
}
}
void LCT() {
int tot = n;
for(int i = 1;i <= m; ++i) {
int u = read(), v = read();
eu[i] = u; ev[i] = v;
if(u == v) {early[i] = i;continue;}
if(find(u) == find(v)) {
int t = Query(u, v); early[i] = val[t];
Cut(eu[early[i]], t); Cut(ev[early[i]], t);
}
++tot; mn[tot] = tot; val[tot] = i;
Link(u, tot); Link(v, tot);
}
//for(int i = 1; i <= m; ++i) cout<<early[i]<<" ";
//cout<<endl;
for(int i = 1;i <= m; ++i) add(0, m, root[i - 1], root[i], early[i]);
}
int query(int L, int R, int lt, int rt, int val) {
if(R == val) return sum[rt] - sum[lt];
int mid = L + R >> 1;
if(val <= mid) return query(L, mid, lc[lt], lc[rt], val);
else return sum[lc[rt]] - sum[lc[lt]] + query(mid + 1, R, rc[lt], rc[rt], val);
}
void PST() {
int lastans = 0;
while(Q--) {
int l = read(), r = read();
if(type) l ^= lastans, r ^= lastans;
lastans = n - query(0, m, root[l - 1], root[r], l - 1);
printf("%d\n", lastans);
}
}
int main()
{
n = read(); m = read(); Q = read(); type = read(); val[0] = inf;
for(int i = 1;i <= n; ++i) mn[i] = i, val[i] = inf;
LCT(); PST();
return 0;
}