N個點M條邊的無向圖,詢問保留圖中編號在[l,r]的邊的時候圖中的聯通塊個數。node
第一行四個整數N、M、K、type,表明點數、邊數、詢問數以及詢問是否加密。
接下來M行,表明圖中的每條邊。
接下來K行,每行兩個整數L、R表明一組詢問。對於type=0的測試點,讀入的L和R即爲詢問的L、R;對於type=1的測試點,每組詢問的L、R應爲L xor lastans和R xor lastans。c++
K行每行一個整數表明該組詢問的聯通塊個數。測試
3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2加密
2
1
3
1spa
對於100%的數據,1≤N、M、K≤200,000。code
2016.2.26提升時限至60sip
考慮怎麼解決聯通塊個數input
首先咱們若是從左向右掃全部的邊加進聯通塊中it
能夠用LCT維護一個動態的生成樹io
而後一旦出現環就刪除環中編號最小的一個邊
而後咱們考慮一下左端點若是大於當前刪除的邊的編號,實際上仍是存在這個聯通塊的
因此說咱們只須要統計在\([l,r]\)這個區間中左端點小於\(l\)的個數就能夠知道有多少個聯通塊了
而後噹噹前節點存在自環的時候就會發現他的刪除的邊的編號就是本身,否則會有多餘的貢獻
而後主席樹維護就沒了
#include<bits/stdc++.h> using namespace std; const int N = 4e5 + 10; int n, m, k, typ; int u[N], v[N]; int lastans = 0; namespace Link_Cut_Tree { int ch[N][2], fa[N], minval[N], val[N], rev[N], cnt = 0; bool isroot(int t) { return ch[fa[t]][0] != t && ch[fa[t]][1] != t; } void pushup(int t) { minval[t] = val[t]; if (ch[t][0]) minval[t] = min(minval[t], minval[ch[t][0]]); if (ch[t][1]) minval[t] = min(minval[t], minval[ch[t][1]]); } void pushnow(int t) { swap(ch[t][0], ch[t][1]); rev[t] ^= 1; } void pushdown(int t) { if (!isroot(t)) pushdown(fa[t]); if (rev[t]) { pushnow(ch[t][0]); pushnow(ch[t][1]); rev[t] = 0; } } void newnode(int vl) { ++cnt; fa[cnt] = ch[cnt][0] = ch[cnt][1] = 0; minval[cnt] = val[cnt] = vl; rev[cnt] = 0; } bool son(int t) { return t == ch[fa[t]][1]; } void rotate(int t) { int f = fa[t], g = fa[f]; bool a = son(t), b = a ^ 1; if (!isroot(f)) ch[g][son(f)] = t; fa[t] = g; ch[f][a] = ch[t][b]; fa[ch[t][b]] = f; ch[t][b] = f; fa[f] = t; pushup(f); pushup(t); } void splay(int t) { pushdown(t); while (!isroot(t)) { int f = fa[t]; if (!isroot(f)) { if (son(f) ^ son(t)) rotate(t); else rotate(f); } rotate(t); } } void access(int t) { int tmp = 0; // 須要設定初值 while (t) { splay(t); ch[t][1] = tmp; pushup(t); tmp = t; t = fa[t]; } } void makeroot(int t) { access(t); splay(t); pushnow(t); } void link(int x, int y) { makeroot(x); fa[x] = y; } void cut(int x, int y) { makeroot(x); access(y); splay(y); fa[x] = ch[y][0] = 0; pushup(y); } }; using Link_Cut_Tree::minval; using Link_Cut_Tree::newnode; using Link_Cut_Tree::link; using Link_Cut_Tree::cut; using Link_Cut_Tree::makeroot; using Link_Cut_Tree::access; namespace Functional_Segment_Tree { const int LOG = 30; int cnt = 0; int siz[N * LOG], ls[N * LOG], rs[N * LOG], rt[N]; void insert(int &t, int last, int l, int r, int pos) { t = ++cnt; ls[t] = ls[last]; rs[t] = rs[last]; siz[t] = siz[last] + 1; if (l == r) return; int mid = (l + r) >> 1; if (pos <= mid) insert(ls[t], ls[last], l, mid, pos); else insert(rs[t], rs[last], mid + 1, r, pos); } int query(int t, int last, int l, int r, int ql, int qr) { if (ql <= l && r <= qr) return siz[t] - siz[last]; int mid = (l + r) >> 1; if (qr <= mid) return query(ls[t], ls[last], l, mid, ql, qr); else if (ql > mid) return query(rs[t], rs[last], mid + 1, r, ql, qr); else return query(ls[t], ls[last], l, mid, ql, mid) + query(rs[t], rs[last], mid + 1, r, mid + 1, qr); } }; using Functional_Segment_Tree::rt; using Functional_Segment_Tree::insert; using Functional_Segment_Tree::query; namespace Union_Find { int fa[N << 1]; void init() { for (int i = 1; i <= n; i++) fa[i] = i; } int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } bool merge(int x, int y) { int fax = find(x), fay = find(y); if (fax == fay) return 0; fa[fax] = fay; return 1; } } using Union_Find::init; using Union_Find::merge; int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif scanf("%d %d %d %d", &n, &m, &k, &typ); for (int i = 1; i <= n; i++) newnode(m + 1); for (int i = 1; i <= m; i++) newnode(i); init(); for (int i = 1; i <= m; i++) { scanf("%d %d", &u[i], &v[i]); if (u[i] == v[i]) { insert(rt[i], rt[i - 1], 0, m, i); continue; } if (merge(u[i], v[i])) { insert(rt[i], rt[i - 1], 0, m, 0); link(u[i], n + i); link(v[i], n + i); } else { makeroot(u[i]); access(v[i]); makeroot(v[i]); int cur = minval[v[i]]; cut(v[cur], n + cur); cut(u[cur], n + cur); link(v[i], n + i); link(u[i], n + i); insert(rt[i], rt[i - 1], 0, m, cur); } } for (int i = 1; i <= k; i++) { int l, r; scanf("%d %d", &l, &r); if (typ) l ^= lastans, r ^= lastans; if (l > r) swap(l, r); lastans = n - query(rt[r], rt[l - 1], 0, m, 0, l - 1); printf("%d\n", lastans); } return 0; }