地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3514
题目:
3514: Codechef MARCH14 GERALD07加强版
Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 1822 Solved: 703
[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
思路:
想了二十分钟后果断滚去看题解了。
有一个比较猎奇的做法:首先把边依次加到图中,若当前这条边与图中的边形成了环,那么把这个环中最早加进来的边弹出去
并将每条边把哪条边弹了出去记录下来:ntr[i] = j,特别地,要是没有弹出边,ntr[i] = 0;
这个显然是可以用LCT来弄的对吧。
然后对于每个询问,我们的答案就是对l~r中ntr小于l的边求和,并用n减去这个值
正确性可以YY一下:
如果一条边的ntr >= l,那么显然他可以与从l ~ r中的边形成环,那么它对答案没有贡献
反之如果一条边的ntr < l那么它与从l ~ r中的边是不能形成环的,那么他对答案的贡献为-1
对于查询从l ~ r中有多少边的ntr小于l,我反正是用的函数式线段树
lct+主席树,好神啊。
主席树开200007*20居然re,说好的nlogn呢。
1 /************************************************************** 2 Problem: 3514 3 User: weeping 4 Language: C++ 5 Result: Accepted 6 Time:45408 ms 7 Memory:110692 kb 8 ****************************************************************/ 9 10 #include <bits/stdc++.h> 11 12 using namespace std; 13 14 const int K = 300007 * 20; 15 16 struct Link_Cut_Tree 17 { 18 static const int MAXN = 500000 + 7; 19 20 int ch[MAXN][2], fa[MAXN], rev[MAXN], v[MAXN], mx[MAXN] ,id[MAXN]; 21 int sk[MAXN]; 22 23 bool isroot(int x) 24 { 25 return ch[fa[x]][0] != x && ch[fa[x]][1] != x; 26 } 27 28 void reverse(int x) 29 { 30 rev[x] ^= 1, swap(ch[x][0],ch[x][1]); 31 } 32 33 void update(int x) 34 { 35 int lc = ch[x][0], rc = ch[x][1]; 36 mx[x] = v[x], id[x] = x; 37 if(lc&&mx[lc]<mx[x]) 38 mx[x] = mx[lc], id[x] = id[lc]; 39 if(rc&&mx[rc]<mx[x]) 40 mx[x] = mx[rc], id[x] = id[rc]; 41 } 42 43 void push_down(int x) 44 { 45 if(!rev[x]) return ; 46 if(ch[x][0]) reverse(ch[x][0]); 47 if(ch[x][1]) reverse(ch[x][1]); 48 rev[x]=0; 49 } 50 51 void rotate(int x) 52 { 53 int f = fa[x], gf = fa[f]; 54 int t1 = ( x != ch[f][0]), t2 = ( f != ch[gf][0]), tmp = ch[x][1^t1]; 55 if(!isroot(f)) ch[gf][0^t2] = x; 56 fa[tmp] = f, fa[x] = gf, ch[x][1^t1] = f, fa[f] = x, ch[f][0^t1] = tmp; 57 update(f); 58 } 59 60 void splay(int x) 61 { 62 int top = 0; 63 sk[++top] = x; 64 for(int i = x; !isroot(i); i = fa[i]) sk[++top] = fa[i]; 65 while(top) push_down(sk[top--]); 66 for(int f = fa[x], gf = fa[f]; !isroot(x); rotate(x), f = fa[x],gf = fa[f]) 67 if(!isroot(f)) 68 rotate((x==ch[f][0]) ^ (f==ch[gf][0]) ? x : f); 69 update(x); 70 } 71 72 void access(int x) 73 { 74 for(int p = 0; x; p = x, x = fa[x]) 75 splay(x), ch[x][1] = p, update(x); 76 } 77 78 void makeroot(int x) 79 { 80 access(x), splay(x), reverse(x); 81 } 82 83 int findroot(int x) 84 { 85 access(x), splay(x); 86 while(ch[x][0]) x = ch[x][0]; 87 return x; 88 } 89 void link(int x,int y) 90 { 91 makeroot(x), fa[x] = y; 92 } 93 94 void cut(int x,int y) 95 { 96 makeroot(x), access(y), splay(y); 97 if(ch[y][0] == x) ch[y][0] = fa[x] = 0; 98 update(y); 99 } 100 101 int go(int u,int v,int n,int m,int k) 102 { 103 if(u==v) 104 return m+2; 105 if(findroot(u)!=findroot(v)) 106 { 107 link(u,k+n),link(v,k+n); 108 return 1; 109 } 110 makeroot(u),access(v),splay(v); 111 int p = id[v]; 112 splay(p); 113 fa[ch[p][0]] = fa[ch[p][1]] = 0; 114 ch[p][0] = ch[p][1] = 0; 115 link(u,k+n),link(v,k+n); 116 return p-n+1; 117 } 118 }lct; 119 120 121 int tot,ls[K],rs[K],rt[K],sum[K]; 122 123 void build(int &o,int l,int r) 124 { 125 o=++tot,sum[o]=0; 126 int mid=l+r>>1; 127 if(l!=r) 128 build(ls[o],l,mid),build(rs[o],mid+1,r); 129 } 130 void update(int &o,int l,int r,int last,int x) 131 { 132 o=++tot,sum[o]=sum[last]+1; 133 ls[o]=ls[last],rs[o]=rs[last]; 134 if(l==r) return ; 135 int mid=l+r>>1; 136 if(x<=mid) update(ls[o],l,mid,ls[last],x); 137 else update(rs[o],mid+1,r,rs[last],x); 138 } 139 int query(int lo,int ro,int l,int r,int k) 140 { 141 if(r<=k) return sum[ro]-sum[lo]; 142 if(l>k) return 0; 143 int mid=l+r>>1; 144 return query(ls[lo],ls[ro],l,mid,k) + query(rs[lo],rs[ro],mid+1,r,k); 145 } 146 147 int main(void) 148 { 149 //freopen("in.acm","r",stdin); 150 int n,m,k,tp; 151 scanf("%d%d%d%d",&n,&m,&k,&tp); 152 for(int i=1;i<=n;i++) lct.v[i] = lct.mx[i] = m + 2, lct.id[i] = i; 153 build(rt[0],1,m+2); 154 for(int i=1,x,y;i<=m;i++) 155 { 156 scanf("%d%d",&x,&y); 157 lct.v[i+n]=lct.mx[i+n]=i,lct.id[i+n]=i+n; 158 update(rt[i],1,m+2,rt[i-1],lct.go(x,y,n,m,i));; 159 } 160 int l,r,ls=0; 161 while(k--) 162 { 163 scanf("%d%d",&l,&r); 164 if(tp) l^=ls,r^=ls; 165 ls=n-query(rt[l-1],rt[r],1,m+2,l); 166 printf("%d ",ls); 167 } 168 return 0; 169 }