zoukankan      html  css  js  c++  java
  • 2018.11.04-3988-地理课(geography)

    题目描述:

    地理课上,老师给出了一个巨大的地图,由于世界日新月异,会有一些道路在某一时刻被删除,也会有一些道路在某一时刻被修建。这里的道路均为双向的。

    老师认为,有一些城市被分在了一个连通块中可以相互到达,而有一些城市不能够相互到达。而他想知道,每个时刻所有连通块大小的乘积是多少?

    wzy看到这个地图的时候就蒙了,还好那只上天的喵及时帮助了他。现在他把这个毒瘤的地图拿过来给你,想试试看你能不能求出来。由于答案可能很大,输出乘积mod109+7即可。

    输入:

    第一行两个数n,m,表示有n个点,m个时刻。接下来m行每行三个数,要么是1uv,要么是2uv,分别表示添加一条无向边和删除一条无向边。

    输出:

    共m,每行一个数表示连通块大小乘积mod1,000,000,007

    数据范围:

    subtask1:30pts,n≤1,000,m≤2,000

    subtask2:20pts,满足没有删除操作。

    subtask3:50pts,n,m≤100,000保证没有重边自环,不会删除不存在的边。

    算法标签:线段树

    思路:

    这题是离线算法,因为对于一条边有加入和删除的操作,所以一条边存在的时间是一段区间,把这段区间存入线段树,每次层层修改,关键是返回时要怎么回到这层的初始状态。首先是在并查集的时候不能路径压缩,然后每次记录下这层修改过的值,然后运用启发式合并,所以效率期望是log(nlog2n)。

    以下代码:

    #include<bits/stdc++.h>
    #define il inline
    #define LL long long
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int p=1e9+7,N=1000000;
    int n,m,fa[N];int res[N],ny[N],sz[N];
    struct data{int l,r,op;}t[N+5];
    struct node{int x,x1,num;};
    map<LL,int> ma;vector<LL> b[N<<2];vector<node> v[N<<2];
    il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
    il int getfa(int x){if(fa[x]==x)return x;return getfa(fa[x]);}
    il int ksm(int a,int y){int b=1;while(y){if(y&1)b=(LL)b*(LL)a%p;a=(LL)a*(LL)a%p;y>>=1;}return b;}
    il void insert(int x,int l,int r,int ql,int qr,LL v){
        if(ql<=l&&r<=qr){
            b[x].push_back(v);
            return;
        }
        int mid=(l+r)>>1;
        if(ql<=mid)insert(x<<1,l,mid,ql,qr,v);
        if(mid<qr)insert(x<<1|1,mid+1,r,ql,qr,v);
    }
    void work(int x,int l,int r,int sum){
        if(l==r){
            int tmp=sum;
            for(int i=0;i<b[x].size();i++){
                LL kk=b[x][i];
                int a,b1;a=(int)(kk/N);b1=(int)(kk%N);
                a=getfa(a);b1=getfa(b1);if(a==b1)continue;
                if(sz[a]<sz[b1])swap(a,b1);
                fa[b1]=a;
                tmp=(LL)tmp*(LL)ny[sz[a]]%p*(LL)ny[sz[b1]]%p;
                v[x].push_back((node){a,b1,sz[a]});sz[a]+=sz[b1];
                tmp=(LL)tmp*(LL)sz[a]%p;
            }
            res[l]=tmp;printf("%d
    ",tmp);
            for(int i=v[x].size()-1;i>=0;i--){
                int kk=v[x][i].x;int ss=v[x][i].num;
                int k1=v[x][i].x1;
                fa[k1]=k1;sz[kk]=ss;
            }
            return;
        }
        int mid=(l+r)>>1;int tmp=sum;
        for(int i=0;i<b[x].size();i++){
            LL kk=b[x][i];
            int a,b1;a=(int)(kk/N);b1=(int)(kk%N);
            
            a=getfa(a);b1=getfa(b1);if(a==b1)continue;
            if(sz[a]<sz[b1])swap(a,b1);
            fa[b1]=a;
            tmp=(LL)tmp*(LL)ny[sz[a]]%p*(LL)ny[sz[b1]]%p;
            v[x].push_back((node){a,b1,sz[a]});sz[a]+=sz[b1];
            tmp=(LL)tmp*(LL)sz[a]%p;
        }
        work(x<<1,l,mid,tmp);work(x<<1|1,mid+1,r,tmp);
        for(int i=v[x].size()-1;i>=0;i--){
            int kk=v[x][i].x;int ss=v[x][i].num;
            int k1=v[x][i].x1;
            fa[k1]=k1;sz[kk]=ss;
        }
    }
    int main()
    {
        n=read();m=read();ny[1]=1;for(int i=2;i<=n;i++)ny[i]=ksm(i,p-2);
        for(int i=1;i<=m;i++){
            t[i].op=read();
            int x=read(),y=read();
            if(x>y)swap(x,y);
            t[i].l=x;t[i].r=y;
            LL kk=(LL)x*(LL)N+y;
            if(ma[kk]==0)ma[kk]=i;
            else{
                insert(1,1,m,ma[kk],i-1,kk);
                ma[kk]=0;
            }
        }
        for(int i=1;i<=m;i++){
            if(t[i].op==1){
                int x=t[i].l,y=t[i].r;
                LL kk=(LL)x*(LL)N+y;
                if(ma[kk]>0){
                    insert(1,1,m,ma[kk],m,kk),ma[kk]=0;
                }
            }
        }
        for(int i=1;i<=n;i++)sz[i]=1,fa[i]=i;
        work(1,1,m,1);
        
        return 0;
    }
    View Code

    此代码跑了30s,慢的一b,仅供参考把

  • 相关阅读:
    线性代数(不完全)与矩阵合集
    最短路合集
    [SP2878]KNIGHTS
    Noip 提高组系列题解目录
    【code】最小费用最大流(Dinic / zkw) 模板
    题解 DTOJ #1002.调整(tweak)
    题解 DTOJ #1008.生成输入数据 (input)
    题解 DTOJ #3861.基里巴斯(path)
    模板 · ISAP网络流+GAP优化+弧优化
    代码 · DTOJ.飞行员配对方案
  • 原文地址:https://www.cnblogs.com/Jessie-/p/9904379.html
Copyright © 2011-2022 走看看