Read problems statements in Mandarin Chinese and Russian.
Problem Statement
Chef has a undirected graph G. This graph consists of N vertices and M edges. Each vertex of the graph has an unique index from 1 to N, also each edge of the graph has an unique index from 1 to M.
Also Chef has Q pairs of integers: Li, Ri (1 ≤ Li ≤ Ri ≤ M). For each pair Li, Ri, Chef wants to know: how many connected components will contain graph G if Chef erase all the edges from the graph, except the edges with indies X, where Li ≤ X ≤ Ri. Please, help Chef with these queries.
Input
The first line of the input contains an integer T denoting the number of test cases. The description of T test cases follows.
The first line of each test case contains three integers N, M, Q. Each of the next M lines contains a pair of integers Vi, Ui - the current edge of graph G. Each of the next Q lines contains a pair of integers Li, Ri - the current query.
Output
For each query of each test case print the required number of connected components.
Constraints
- 1 ≤ T ≤ 1000.
- 1 ≤ N, M, Q ≤ 200000.
- 1 ≤ Ui, Vi ≤ N.
- 1 ≤ Li ≤ Ri ≤ M.
- Sum of all values of N for test cases is not greater than 200000. Sum of all values of M for test cases is not greater than 200000. Sum of all values of Q for test cases is not greater than 200000.
- Graph G can contain self-loops and multiple edges.
Example
Input: 2 3 5 4 1 3 1 2 2 1 3 2 2 2 2 3 1 5 5 5 1 2 1 1 1 1 1 1 1 Output: 2 1 3 1 1
破题坑了一晚上
题目大意?见上面超链接的中文题面。
树 LCT 动态维护生成树
将所有询问按右端点递增顺序排序,从1到m依次加边。
用LCT维护当前的生成树,生成树中保留的是编号尽量大的边。
同时用线段树维护生成树中保留了哪些边(权值线段树,存编号)。
查询时,在线段树上查询$[L,R]$范围内有多少条边,若查询结果为$ x $,则连通块数为$n-x$
注意有自环和重边,这使得维护生成树的时候不能一律删编号最靠前的边,而要先查询生成树中有没有重边。
细节蛮多的。
注意多组数据,初始化结点的时候要初始化到n+m
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 #define LL long long 7 using namespace std; 8 const int INF=0x3f3f3f3f; 9 const int mxn=420010; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 struct edge{ 17 int x,y; 18 }e[mxn]; 19 struct query{ 20 int L,R; 21 int id; 22 bool operator < (const query &b)const{ 23 return R<b.R; 24 } 25 }q[mxn]; 26 int ans[mxn]; 27 // 28 struct SGT{ 29 int smm[mxn<<2]; 30 #define ls rt<<1 31 #define rs rt<<1|1 32 void clear(int ed){ 33 ed=ed<<2; 34 for(register int i=0;i<=ed;i++)smm[i]=0; 35 } 36 void pushup(int rt){smm[rt]=smm[ls]+smm[rs];return;} 37 void update(int p,int v,int l,int r,int rt){ 38 if(l==r){ 39 smm[rt]+=v; 40 return; 41 } 42 int mid=(l+r)>>1; 43 if(p<=mid)update(p,v,l,mid,ls); 44 else update(p,v,mid+1,r,rs); 45 pushup(rt); 46 return; 47 } 48 int query(int L,int R,int l,int r,int rt){ 49 if(L<=l && r<=R){ 50 return smm[rt]; 51 } 52 int mid=(l+r)>>1; 53 if(R<=mid)return query(L,R,l,mid,ls); 54 if(L>mid)return query(L,R,mid+1,r,rs); 55 return query(L,R,l,mid,ls)+query(L,R,mid+1,r,rs); 56 } 57 #undef ls 58 #undef rs 59 }SG; 60 int n,m,Q; 61 // 62 struct node{ 63 int ch[2],fa; 64 int val,mn,minpos; 65 bool rev; 66 }t[mxn]; 67 int cnt=0; 68 void rever(int x){ 69 int &lc=t[x].ch[0],&rc=t[x].ch[1]; 70 swap(lc,rc); 71 t[lc].rev^=1;t[rc].rev^=1; 72 return; 73 } 74 void PD(int x){ 75 if(t[x].rev){ 76 rever(x); 77 t[x].rev=0; 78 } 79 return; 80 } 81 void pushup(int x){ 82 int lc=t[x].ch[0],rc=t[x].ch[1]; 83 t[x].mn=t[x].val;t[x].minpos=x; 84 if(t[lc].mn<t[x].mn){ 85 t[x].mn=t[lc].mn; t[x].minpos=t[lc].minpos; 86 } 87 if(t[rc].mn<t[x].mn){ 88 t[x].mn=t[rc].mn; t[x].minpos=t[rc].minpos; 89 } 90 return; 91 } 92 inline bool isroot(int x){ 93 return (t[t[x].fa].ch[0]^x)&&(t[t[x].fa].ch[1]^x); 94 } 95 void rotate(int x){ 96 int y=t[x].fa,z=t[y].fa,lc,rc; 97 if(t[y].ch[0]==x)lc=0;else lc=1;rc=lc^1; 98 if(!isroot(y)){ 99 t[z].ch[t[z].ch[1]==y]=x; 100 } 101 t[x].fa=z;t[y].fa=x; 102 t[t[x].ch[rc]].fa=y; 103 t[y].ch[lc]=t[x].ch[rc]; 104 t[x].ch[rc]=y; 105 pushup(y); 106 return; 107 } 108 int st[mxn],top=0; 109 void Splay(int x){ 110 st[top=1]=x; 111 for(int i=x;t[i].fa;i=t[i].fa){ 112 st[++top]=t[i].fa; 113 } 114 while(top)PD(st[top--]); 115 while(!isroot(x)){ 116 int y=t[x].fa,z=t[y].fa; 117 if(!isroot(y)){ 118 if((t[y].ch[0]==x)^(t[z].ch[0]==y))rotate(x); 119 else rotate(y); 120 } 121 rotate(x); 122 } 123 pushup(x); 124 return; 125 } 126 // 127 void access(int x){ 128 for(int y=0;x;x=t[x].fa){ 129 Splay(x); 130 t[x].ch[1]=y; 131 pushup(x); 132 y=x; 133 } 134 return; 135 } 136 int find(int x){ 137 access(x);Splay(x); 138 while(t[x].ch[0]){ 139 x=t[x].ch[0]; 140 } 141 return x; 142 } 143 void mkroot(int x){ 144 access(x);Splay(x); 145 t[x].rev^=1; 146 return; 147 } 148 void link(int x,int y){ 149 mkroot(x); t[x].fa=y; 150 return; 151 } 152 void cut(int x,int y){ 153 mkroot(x); 154 access(y);Splay(y); 155 if(t[y].ch[0]==x){t[x].fa=0;t[y].ch[0]=0;} 156 pushup(y); 157 return; 158 } 159 // 160 void solve(){ 161 int hd=1; 162 cnt=n; 163 for(int i=1;i<=m;i++){//按序加边 164 int x=e[i].x,y=e[i].y; 165 if(x!=y && find(x)==find(y)){ 166 bool flag=0; 167 mkroot(x);access(y);Splay(y); 168 // 169 /* printf("----- "); 170 for(int j=1;j<=cnt;j++){ 171 printf("#%d: lc:%d rc:%d fa:%d ",j,t[j].ch[0],t[j].ch[1],t[j].fa); 172 } 173 printf("----- ");*/ 174 // 175 int res=t[y].ch[0]; 176 while(t[res].ch[1])res=t[res].ch[1]; 177 res=res-n; 178 if(res>0 && e[res].x==x && e[res].y==y){ 179 flag=1; 180 cut(x,res+n); 181 cut(y,res+n); 182 SG.update(res,-1,1,m,1); 183 } 184 // 185 if(!flag){ 186 mkroot(x);access(y);Splay(y); 187 int tar=t[y].minpos; 188 cut(e[tar-n].x,tar); 189 cut(e[tar-n].y,tar); 190 SG.update(tar-n,-1,1,m,1); 191 } 192 } 193 ++cnt; 194 if(x!=y){ 195 t[cnt].val=t[cnt].mn=i; 196 t[cnt].minpos=cnt; 197 link(x,cnt); 198 link(cnt,y); 199 SG.update(i,1,1,m,1); 200 } 201 while(hd<=Q && q[hd].R<=i){ 202 if(q[hd].R==i){ 203 ans[q[hd].id]=n-SG.query(q[hd].L,q[hd].R,1,m,1); 204 } 205 hd++; 206 } 207 } 208 return; 209 } 210 void init(int n,int m){ 211 int ed=n+m; 212 t[0].minpos=0;t[0].mn=INF; 213 for(register int x=1;x<=ed;x++){ 214 t[x].ch[0]=t[x].ch[1]=t[x].fa=0; 215 t[x].minpos=0;t[x].mn=INF; 216 t[x].val=INF; 217 t[x].rev=0; 218 } 219 SG.clear(ed); 220 return; 221 } 222 int main(){ 223 // freopen("in.txt","r",stdin); 224 int i; 225 int T=read(); 226 while(T--){ 227 n=read();m=read();Q=read(); 228 init(n,m); 229 for(i=1;i<=m;i++){ 230 e[i].x=read();e[i].y=read(); 231 if(e[i].x>e[i].y)swap(e[i].x,e[i].y); 232 } 233 for(i=1;i<=Q;i++){ 234 q[i].L=read();q[i].R=read(); 235 q[i].id=i; 236 } 237 sort(q+1,q+Q+1); 238 solve(); 239 for(i=1;i<=Q;i++){ 240 printf("%d ",ans[i]); 241 } 242 } 243 return 0; 244 }