1. 程式人生 > >2017icpcBeijing C - Graph

2017icpcBeijing C - Graph

題解: 首先查詢的是邊的編號在[l,r]的有效邊  所以我們可以轉化成將邊的標號大於等於l的邊與邊的編號小於等於r的邊求交集 則為查詢的有效邊 發現維護是用並查集維護 加邊是Log 刪邊是on的  所以我們考慮離線以後回滾莫隊處理答案即可 注意細節就行

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=1e5+10;
const double eps=1e-8;
#define ll long long
using namespace std;
struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;}
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
typedef struct node{
    int l,r,id;
}node;
node st[MAXN];
int tot;
ll ans[MAXN];
bool cmp1(node aa,node bb){
	if(aa.l==bb.l)return aa.r>bb.r;
    return aa.l>bb.l;
}
bool cmp2(node aa,node bb){
    if(aa.r==bb.r)return aa.l<bb.l;
    return aa.r<bb.r;
}
node d1[MAXN],d2[MAXN],que[MAXN<<1];
int f[MAXN],p[MAXN];
int vis[MAXN],num[MAXN];
vector<node>vec[MAXN];
int find1(int x){
    if(x==f[x])return x;
    else return find1(f[x]);
}
int main(){
    int _=read();
    while(_--){
        int n,m,q;n=read();m=read();q=read();
        int sz=sqrt(m);memset(ans,0,sizeof(ans));
        inc(i,1,m)p[i]=(i-1)/sz+1,vec[i].clear();
        inc(i,1,n)f[i]=i,num[i]=1;
        int t1,t2;
        inc(i,1,m)t1=read(),t2=read(),d1[i].l=min(t1,t2),d1[i].r=max(t1,t2),d1[i].id=i,d2[i]=d1[i],vis[i]=0;
        inc(i,1,q)que[i].l=read(),que[i].r=read(),que[i].id=i,ans[i]=0;
        sort(d1+1,d1+m+1,cmp1);sort(d2+1,d2+m+1,cmp2);
        inc(i,1,q){
            int l=1;int r=m;int ans1=0;
            while(l<=r){
                int mid=(l+r)>>1;
                if(d1[mid].l>=que[i].l)l=mid+1,ans1=mid;
                else r=mid-1;
            }
            if(ans1)vec[p[ans1]].pb(que[i]);
        }
        inc(i,1,p[m])sort(vec[i].begin(),vec[i].end(),cmp2);
        ll ans2=0;
        inc(i,1,p[m]){
            if(!vec[i].size()){
                ans2=0;
                for(int j=(i-1)*sz+1;j<=min(m,i*sz);j++){
                    vis[d1[j].id]++;
                }
                continue;
            }
            int L=(i-1)*sz+1;int R=1;
            for(int j=0;j<vec[i].size();j++){
                while(R<=m&&d2[R].r<=vec[i][j].r){
                    vis[d2[R].id]++;
                    if(vis[d2[R].id]==2){
                        int t1=find1(d2[R].l);int t2=find1(d2[R].r);
                        if(t1!=t2){
                            if(num[t1]>num[t2])swap(t1,t2);
                            f[t1]=t2;
                            ans2+=1ll*num[t1]*num[t2];
                            num[t2]+=num[t1];
                        }
                    }
                    R++;
                }
                tot=0;
                while(L<=m&&d1[L].l>=vec[i][j].l){
                    vis[d1[L].id]++;
                    if(vis[d1[L].id]==2){
                        int t1=find1(d1[L].l);int t2=find1(d1[L].r);
                        if(t1!=t2){
                            if(num[t1]>num[t2])swap(t1,t2);
                            f[t1]=t2;
                            ans2+=1ll*(num[t1])*num[t2];
                            num[t2]+=num[t1];
                            st[++tot]=(node){t1,t2,0};                          
                        }
                    }
                    L++;
                }
                ans[vec[i][j].id]=ans2;
                while(tot){
                    f[st[tot].l]=st[tot].l;
                    num[st[tot].r]-=num[st[tot].l];
                    ans2-=1LL*num[st[tot].l]*num[st[tot].r];
                    tot--;
                }
                int tt=(i-1)*sz+1;
                while(L>=tt){L--;vis[d1[L].id]--;}
                vis[d1[L].id]++;L++; 
            }
            ans2=0;
            for(int j=1;j<=n;j++)f[j]=j,num[j]=1;
            for(int j=1;j<R;j++)if(vis[d2[j].id]>0)vis[d2[j].id]--;
            for(int j=(i-1)*sz+1;j<=min(m,i*sz);j++){
                vis[d1[j].id]++;
            }
        }
        for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
    }
    return 0;
}

 

The country contains N cities numbered from 1 to N and M undirected roads connecting pairs of cities. There are some queries. Each query is represented by two numbers: L and R , meaning that all the cities whose number is between L and R(L and R are included) are safe, and other cities are not safe. We define city A can reach city B if and only if they are both safe and there exists a path from A to B that the cities on the path are all safe.

For each query, you need to figure out the number of pairs of cities that can reach each other under the condition given by the query.

Input

First line contains one number T which means the number of test cases.

For each test case, first line contains three numbers, above mentioned N , M and Q.

Next M lines, each line contains two integers: X, Y (X != Y) which means there is a road between city X and city Y (1 <= X,Y <= N).

Next Q lines, each line contains two numbers: L, R which indicates an query(1 <= L,R <= N, L <= R).

T <= 5, N , M <= 50000, Q <= 100000

Output

For each test case, output Q lines, each line contains the answer of the correspondent query.

Sample Input

1
6 6 4
1 2
2 3
2 6
1 5
2 4
4 5
1 4
3 6
2 6
3 4

Sample Output

6
1
10
0