zoukankan      html  css  js  c++  java
  • cf 1416D. Graph and Queries (生成树重构+线段树维护dfs序)

    题目链接:传送门

    题目思路:思路参考博客 https://www.cnblogs.com/EchoZQN/p/13804989.html

         对于这种题,首先会思考如何转化删边,常用的就是把所有的查询和修改作逆序处理,然后并查集求解,但是这道题由于有修改(查询一个最大值后删除),因此不能采用这个方法。

         那么这道题可以采用类似于kruskal 生成树重构的方法建图,那么对于每一个连通块的所有点都是位于同一棵子树的(子树的根是连通块的祖先节点),不论是删边前的大连通块,还是删边后可能形成的小连通块,这样以来也能保证每一个连通块的所有dfs序是连续的,那么就可以用线段树来维护最值了。

    代码:

    #include<bits/stdc++.h>
    #pragma GCC optimize(2)
    using namespace std;
    typedef long long LL;
    typedef unsigned long long uLL;
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pLL;
    typedef pair<double,double> pdd;
    const int N=5e5+5;
    const int M=8e5+5;
    const int inf=0x3f3f3f3f;
    const LL mod=1e8+7;
    const double eps=1e-8;
    const long double pi=acos(-1.0L);
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define fi first
    #define se second
    #define pb push_back
    #define eb emplace_back
    #define mk make_pair
    #define mem(a,b) memset(a,b,sizeof(a))
    LL read()
    {
        LL x=0,t=1;
        char ch;
        while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
        while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
        return x*t;
    
    }
    int n,m,q,p[N],f[N],vis[N],id,pp[N];
    pii a[N],b[N];
    int rt[N],c[N<<2],in[N],out[N],rk[N],now;
    vector<int> e[N];
    int getf(int x)
    {
        return f[x]==x?f[x]:f[x]=getf(f[x]);
    }
    void build(int i,int l,int r)
    {
        if(l==r) return (void)(c[i]=p[rk[l]]);
        int mid=l+r>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        c[i]=max(c[ls],c[rs]);
    }
    void update(int i,int l,int r,int pos,int x)
    {
        if(l==r) return (void)(c[i]=x);
        int mid=l+r>>1;
        if(pos<=mid) update(ls,l,mid,pos,x);
        else update(rs,mid+1,r,pos,x);
        c[i]=max(c[ls],c[rs]);
    }
    int query(int i,int l,int r,int ll,int rr)
    {
        if(ll<=l&&r<=rr) return c[i];
        int mid=l+r>>1,t1=0,t2=0;
        if(mid>=ll) t1=query(ls,l,mid,ll,rr);
        if(mid<rr) t2=query(rs,mid+1,r,ll,rr);
        return max(t1,t2);
    }
    void dfs(int u)
    {
       // printf("u = %d
    ",u);
        in[u]=++id;
        rk[id]=u;
        for(auto v:e[u]) dfs(v);
        out[u]=id;
    }
    int main()
    {
        n=read(),m=read(),q=read();
        for(int i=1;i<=n;i++) p[i]=read();
        for(int i=1;i<=n;i++) pp[p[i]]=i;
        for(int i=1;i<=n;i++) f[i]=i;
        for(int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            a[i]=mk(x,y);
        }
        for(int i=1;i<=q;i++)
        {
            int x=read(),y=read();
            b[i]=mk(x,y);
            if(x==2) vis[y]=1;
        }
        now=n;
        for(int i=1;i<=m;i++)
        {
            if(vis[i]) continue;
            int x=getf(a[i].fi),y=getf(a[i].se);
            if(x==y) continue;
            f[now]=++now;
            f[x]=f[y]=now;
            e[now].eb(x);
            e[now].eb(y);
        }
        for(int i=q;i;i--)
        {
            if(b[i].fi==2)
            {
                int j=b[i].se;
                int x=getf(a[j].fi),y=getf(a[j].se);
                if(x==y) continue;
                f[now]=++now;
                f[x]=f[y]=now;
                e[now].eb(x);
                e[now].eb(y);
            }
            else rt[i]=getf(b[i].se);//对于i时刻来说 1~i-1这段时间 边已经断掉了,此时祖先代表了这个小的连通块;也可以给每个点加入时间权,自底向上权值不上升,采用树上倍增即可
        }
        for(int i=1;i<=now;i++)
            if(i==f[i]) dfs(i);
    
        build(1,1,now);
        for(int i=1;i<=q;i++)
        {
            if(b[i].fi==2) continue;
            //printf("rt = %d
    ",rt[i]);
            int ans=query(1,1,now,in[rt[i]],out[rt[i]]);
            printf("%d
    ",ans);
            //printf("%d %d
    ",ans,in[pp[ans]]);
            if(ans) update(1,1,now,in[pp[ans]],0);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    支付宝沙箱环境应用
    七牛云视频托管
    腾讯云短息验证码接口
    git远程连接(码云)
    git
    字间距
    html文本保留空格
    mysql重启导致AUTO_INCREMENT从1开始
    js保留两位小数
    vue中watch的基本用法
  • 原文地址:https://www.cnblogs.com/DeepJay/p/13941887.html
Copyright © 2011-2022 走看看