zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第八场) E 线段树+可撤销并查集

    题目传送门

    题意:

      给出m条无向边,每条边都有一个$[l,r]$,意思是体积在这个范围内的人才能通过这条边,询问有多少种体积的可能性,能使人从1到n

    思路:由于是无向边,1和n的连通性可以用并查集维护。

      考虑最暴力的做法,枚举每一种体积,将当前体积能通过的边用并查集维护一下,判断1到n的连通性即可。

      考虑优化,首先区间必定可以离散化,并且我们可以将离散化后的区间按照线段树的方式划分一下,然后将每一个子区间的边用并查集连一下,判断连通性,然后离开这个子区间时,将并查集的连边操作退回就可以了。

      由于每条边最多被划分成log个区间,也就是会被并查集加入log次,拆开log次,所以时间复杂度是(n*logn*logn),其中一个log是并查集带来的,常数很小。

      可撤销的并查集用按秩合并来完成,并且只能回退连续一段时间的操作,离散化后点有2*n个,线段树点不要开太少。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define dep(i,b,a) for(int i=b;i>=a;i--)
    #define pb(x) push_back(x)
    #define pii pair<int,int >
    using namespace std;
    const int maxn=200010;
    vector<int >tr[maxn<<2];
    int n,m;
    struct edge{
        int u,v,l,r;
    }a[maxn];
    int b[maxn<<1],cnt,ans;
    int fa[maxn],siz[maxn];
    int find(int x){
        return x==fa[x]?x:find(fa[x]);
    }
    void update(int o,int l,int r,int ql,int qr,int i){
        if(ql<=l&&r<=qr){
            tr[o].pb(i);
            return;
        }
        int mid=(l+r)>>1;
        if(ql<=mid)update(o<<1,l,mid,ql,qr,i);
        if(mid<qr)update(o<<1|1,mid+1,r,ql,qr,i);
    }
    void dfs(int o,int l,int r){
        vector<pii >ve;
        int si=tr[o].size();
        rep(i,0,si-1){
            int id=tr[o][i];
            int u=a[id].u,v=a[id].v;
            int fu=find(u),fv=find(v);
            if(fu==fv)continue;
            if(siz[fu]>siz[fv])swap(fu,fv);
            fa[fu]=fv;
            int d=0;
            if(siz[fu]==siz[fv])d++;
            siz[fv]+=d;
            ve.push_back({fu,d});
        }
        int mid=(l+r)>>1;
        if(find(1)==find(n)){
            ans+=b[r+1]-b[l];
        }else if(l<r){
            dfs(o<<1,l,mid);
            dfs(o<<1|1,mid+1,r);
        }
        si=ve.size();
        dep(i,si-1,0){
            siz[fa[ve[i].first]]-=ve[i].second;
            fa[ve[i].first]=ve[i].first;
        }
    }
    int main(){
        cin>>n>>m;
        rep(i,1,n){
            fa[i]=i;
            siz[i]=1;
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d%d%d",&a[i].u,&a[i].v,&a[i].l,&a[i].r);
            b[++cnt]=a[i].l;
            b[++cnt]=a[i].r+1;
        }
        sort(b+1,b+1+cnt);
        cnt=unique(b+1,b+1+cnt)-b-1;
        for(int i=1;i<=m;i++){
            a[i].l=lower_bound(b+1,b+1+cnt,a[i].l)-b;
            a[i].r=lower_bound(b+1,b+1+cnt,a[i].r+1)-b;
            update(1,1,cnt,a[i].l,a[i].r-1,i);
        }
        dfs(1,1,cnt);
        printf("%d
    ",ans);
    }
  • 相关阅读:
    Arctic Network POJ
    Journey CodeForces
    Free Goodies UVA
    MU Puzzle HDU
    Balance POJ
    1sting 大数 递推
    最大报销额 暴力。。
    洛谷P2826 LJJ的数学课
    2018年12月29日
    2018年12月28日
  • 原文地址:https://www.cnblogs.com/mountaink/p/11334120.html
Copyright © 2011-2022 走看看