[CodeChef - GERALD07 ] Chef and Graph Queries

 

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: LiRi (1 ≤ Li ≤ Ri ≤ M). For each pair LiRi, 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 NMQ. Each of the next M lines contains a pair of integers ViUi - the current edge of graph G. Each of the next Q lines contains a pair of integers LiRi - the current query.

Output

For each query of each test case print the required number of connected components.

Constraints

  • 1 ≤ T ≤ 1000.
  • 1 ≤ NMQ ≤ 200000.
  • 1 ≤ UiVi ≤ 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("-----\n");
170             for(int j=1;j<=cnt;j++){
171                 printf("#%d: lc:%d rc:%d fa:%d\n",j,t[j].ch[0],t[j].ch[1],t[j].fa);
172             }
173             printf("-----\n");*/
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\n",ans[i]);
241         }
242     }
243     return 0;
244 }

 

转载于:https://www.cnblogs.com/SilverNebula/p/7056789.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值