题解: 首先查询的是边的编号在[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

转载于:https://www.cnblogs.com/wang9897/p/9882457.html

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐