zoukankan      html  css  js  c++  java
  • 2017北京ICPC C题 Graph

    #1629 : Graph

    时间限制:4000ms
    单点时限:4000ms
    内存限制:256MB

    描述

    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.

    输入

    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

    输出

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

    样例输入
    1
    6 6 4
    1 2
    2 3
    2 6
    1 5
    2 4
    4 5
    1 4
    3 6
    2 6
    3 4
    样例输出
    6
    1
    10
    0
    分析:对于询问(L,R),可行的边(x,y)满足L<=x<=y<=R;
       那么分成两部分,满足L<=x的边与y<=R的边的交即可;
       于是把边拷贝两份分别排序求前缀交,可以离线用回滚莫队转移;
       维护答案用并查集即可;
    代码:
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <climits>
    #include <cstring>
    #include <string>
    #include <set>
    #include <bitset>
    #include <map>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <cassert>
    #include <ctime>
    #define rep(i,m,n) for(i=m;i<=(int)n;i++)
    #define inf 0x3f3f3f3f
    #define mod 19260817
    #define vi vector<int>
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define ll long long
    #define pi acos(-1.0)
    #define pii pair<int,int>
    #define sys system("pause")
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    #define all(x) x.begin(),x.end()
    const int maxn=1e5+10;
    const int N=2e5;
    using namespace std;
    ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
    ll qmul(ll p,ll q,ll mo){ll f=0;while(q){if(q&1)f=(f+p)%mo;p=(p+p)%mo;q>>=1;}return f;}
    ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p%mod;p=p*p%mod;q>>=1;}return f;}
    int n,m,k,t,q,num,bl[maxn],fa[maxn],sz[maxn],cnt[2][maxn],tot,L[maxn],R[maxn];
    ll ret,lst,ans[maxn];
    struct node
    {
        int u,v,id;
        bool operator<(const node&p)const
        {
            return bl[u]==bl[p.u]?v<p.v:bl[u]<bl[p.u];
        }
    }e[maxn],f[maxn],qu[maxn],tmp[maxn];
    bool cmp1(node x,node y)
    {
        return x.u>y.u;
    }
    bool cmp2(node x,node y)
    {
        return x.v<y.v;
    }
    int find(int x){return fa[x]==x?x:find(fa[x]);}
    void unite(int x,int y)
    {
        x=find(x),y=find(y);
        if(x==y)return;
        if(sz[x]>sz[y])swap(x,y);
        fa[x]=y;
        ret+=(ll)sz[y]*sz[x];
        sz[y]+=sz[x];
    }
    void undo()
    {
        while(tot)
        {
            int x=tmp[tot].u,y=tmp[tot].v;
            fa[x]=x;
            sz[y]-=sz[x];
            ret-=(ll)sz[y]*sz[x];
            tot--;
        }
    }
    int main(){
        int i,j;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d%d",&n,&m,&q);
            rep(i,1,m)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                if(x>y)swap(x,y);
                e[i]=f[i]=node{x,y,i};
            }
            sort(e+1,e+m+1,cmp1);
            sort(f+1,f+m+1,cmp2);
            int pos=0;
            for(i=n;i>=1;i--)
            {
                while(pos+1<=m&&e[pos+1].u>=i)pos++;
                L[i]=pos;
            }
            pos=0;
            rep(i,1,n)
            {
                while(pos+1<=m&&f[pos+1].v<=i)pos++;
                R[i]=pos;
            }
            num=round(sqrt(m)+0.5);
            rep(i,1,m)bl[i]=(i-1)/num+1;
            rep(i,1,q)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                if(x>y)swap(x,y);
                qu[i]=node{L[x],R[y],i};
            }
            sort(qu+1,qu+q+1);
            int l,r;
            rep(i,1,q)
            {
                if(i==1||bl[qu[i].u]!=bl[qu[i-1].u])
                {
                    rep(j,1,n)fa[j]=j,sz[j]=1;
                    rep(j,1,m)cnt[0][j]=cnt[1][j]=0;
                    ret=tot=0;
                    j=1;
                    while(j<=m&&j<=bl[qu[i-1].u]*num)++cnt[0][e[j++].id];
                    l=j,r=1;
                }
                while(r<=m&&r<=qu[i].v)
                {
                    if(++cnt[1][f[r].id]==1&&cnt[0][f[r].id])
                    {
                        unite(f[r].u,f[r].v);
                    }
                    r++;
                }
                lst=ret;
                while(l<=m&&l<=qu[i].u)
                {
                    if(++cnt[0][e[l].id]==1&&cnt[1][e[l].id])
                    {
                        int x=find(e[l].u),y=find(e[l].v);
                        if(x!=y)
                        {
                            if(sz[x]>sz[y])swap(x,y);
                            tmp[++tot]=node{x,y,0};
                            unite(x,y);
                        }
                    }
                    l++;
                }
                while(l>j)
                {
                    --cnt[0][e[--l].id];
                }
                ans[qu[i].id]=ret;
                undo();
                ret=lst;
            }
            rep(i,1,q)printf("%lld
    ",ans[i]);
        }
        return 0;
    }
    /*
    1
    3 3 6
    1 2
    2 3
    3 1
    1 1
    2 2
    3 3
    1 2
    2 3
    1 3
    */
  • 相关阅读:
    【C++】对象模型之Function
    linux扩展磁盘
    swift文件操作
    WEEK丢人周
    swift upload
    桌面管理器
    linux 撤销软件卸载
    声明Complex类,成员变量包括实部和虚部,成员方法包括实现由字符串构造复数、复数加法、减法,字符串描述、比较相等等操作
    eclipse踩坑
    QQ语音消息提取 amr文件解密
  • 原文地址:https://www.cnblogs.com/dyzll/p/7887249.html
Copyright © 2011-2022 走看看