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

    地理课(geography)

    题目描述

     

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

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

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

     

    输入

     

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

     

    输出

     

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

     

     

    上面是每个时刻操作后的图。乘积分别为:

    2*1*1*1=2,3*1*1=3,3*1*1=3,3*2=6,5,3*2=6

    数据范围及约定

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

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

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

     

     

     

    来源

    noip2018南外-模拟


    solution

    好题好题

    考虑离线,按时间建一棵线段树

    把每一个边的编号加进线段树对应的区间中

    我们现在希望得到每一个叶子节点的值

    那么每次暴力求是不行了

    我们记下每一层的边连接的并查集的根与大小

    返回时把边拆开即可

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<map>
    #include<vector>
    #define mod 1000000007
    #define maxn 100005
    #define ll long long
    using namespace std;
    int n,m,f[maxn],sz[maxn],t1,t2,op;
    ll now,ans[maxn],ny[maxn];
    struct node{
        int u,v,st,ed;
    }e[maxn];
    map<ll,int>ls;
    struct no{
        int l,r;
        vector<int>x;
    }tree[maxn*8];
    struct Node{
        int id,x,y,size;
    };
    vector<Node>p;
    void build(int k,int L,int R){
        tree[k].l=L,tree[k].r=R;
        if(L==R)return;
        int mid=L+R>>1;
        build(k*2,L,mid);build(k*2+1,mid+1,R);
    }
    void add(int k,int L,int R,int v){
        //cout<<k<<' '<<L<<' '<<R<<''<<endl;
        if(tree[k].l>=L&&tree[k].r<=R){
            tree[k].x.push_back(v);return;
        }
        int mid=tree[k].l+tree[k].r>>1;
        if(L<=mid)add(k*2,L,R,v);
        if(R>mid)add(k*2+1,L,R,v);
    }
    ll work(ll a,int num){
        ll an=1;
        while(num){
            if(num&1)an=an*a;
            a=a*a;a%=mod;an%=mod;num>>=1;
        }
        return an;
    }
    int getf(int k){
        if(f[k]==k)return k;
        return getf(f[k]);
    }
    void hb(int k){
        //cout<<"k: "<<k<<' '<<tree[k].l<<' '<<tree[k].r<<endl;
        for(int i=0;i<tree[k].x.size();i++){
            int t=tree[k].x[i];
            //cout<<t<<endl;
            int f1=getf(e[t].u),f2=getf(e[t].v);
            if(f1!=f2){
                now=now*ny[sz[f1]]%mod*ny[sz[f2]]%mod;
                now=now*(sz[f1]+sz[f2])%mod;
                if(sz[f1]<sz[f2]){
                    p.push_back((Node){k,f1,f2,sz[f1]});
                    f[f1]=f2;sz[f2]+=sz[f1];sz[f1]=0;
                }
                else {
                    p.push_back((Node){k,f2,f1,sz[f2]});
                    f[f2]=f1;sz[f1]+=sz[f2];sz[f2]=0;
                }
            }
        }
    }
    void turn(int k){
        int Size=p.size()-1;if(Size<0)return;
        //cout<<"Size "<<Size<<' '<<tree[k].l<<' '<<tree[k].r<<endl;
        for(int i=Size;p[i].id==k&&i>=0;i--){
            //cout<<p[i].x<<' '<<p[i].y<<' '<<sz[p[i].x]<<' '<<sz[p[i].y]<<endl;
            now=now*ny[sz[p[i].y]]%mod;
            f[p[i].x]=p[i].x;sz[p[i].x]=p[i].size;sz[p[i].y]-=sz[p[i].x];
            now=now*sz[p[i].x]%mod*sz[p[i].y]%mod;
            p.pop_back();
        }
    }
    void dfs(int k){
        hb(k);
        if(tree[k].l==tree[k].r){
            ans[tree[k].l]=now;turn(k);
            return;
        }
         
        dfs(k*2);dfs(k*2+1);
        turn(k);
    }
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&op,&e[i].u,&e[i].v);
            if(e[i].u>e[i].v)swap(e[i].u,e[i].v);
            ll tmp=(ll)e[i].u*100000+e[i].v;
            if(op==1){ls[tmp]=i;e[i].st=i;}
            else {
                int la=ls[tmp];e[la].ed=i-1;
                //ls[tmp]=0;
            }
        }
        build(1,1,m);
        for(int i=1;i<=m;i++){
            if(e[i].ed==0)e[i].ed=m;
            if(e[i].st&&e[i].ed)add(1,e[i].st,e[i].ed,i);
        }
        for(int i=1;i<=n;i++)ny[i]=work(i,mod-2);
        for(int i=1;i<=n;i++)f[i]=i,sz[i]=1;
        now=1;dfs(1);
        for(int i=1;i<=m;i++)printf("%lld
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    优雅的windowsC++项目的配置
    C++实现编码转换
    C++读取配置文件
    完全依赖QML实现播放器
    记一次和“N+1”的擦肩而过
    FFmpeg4.0笔记:采集系统声音
    FFmpeg4.0笔记:采集桌面
    FFmpeg4.0笔记:封装ffmpeg的解封装功能类CDemux
    SDL2:封装媒体显示播放Csdl2
    FFmpeg4.0笔记:封装ffmpeg的音频重采样功能类CSwr
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358779.html
Copyright © 2011-2022 走看看