zoukankan      html  css  js  c++  java
  • 题解 洛谷 P5385 【[Cnoi2019]须臾幻境】

    首先我们知道 (n) 个点的树有 (n-1) 条边,因此对于森林来说,其点数减边数即为树的个数。那么对于普通的图,求出其任意一个生成树森林,森林中树的个数即为原图中连通块的个数,也就是点数减边数。

    因此问题就转化为了如何快速求出一个图的生成树森林的边数。

    考虑用 (LCT) 来维护原图的一个生成树森林。按顺序加边,当发现两端点已经连通,要形成环时,就删去环上最早加入的一条边。同时用主席树来维护每条边是否在当前的生成树森林中出现。

    询问时在 (r) 所对应的主席树上查询区间 ([l,r]) 中有几条边存在,存在的边数即为对应的生成树森林的边数,用 (n) 减去边数即为答案。

    因为 (LCT) 维护的是以时间为边权的最大生成树森林,所以每条边都尽可能的选用出现时间晚的,这就使得 (r) 所对应的主席树中区间 ([l,r]) 中边的出现是最多的,所以就保证了正确性。

    (code:)

    #include<bits/stdc++.h>
    #define maxn 400010
    #define maxm 12000010
    #define inf 1000000000
    #define mid ((l+r)>>1)
    using namespace std;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,m,q,t,ans,tree_cnt;
    int ls[maxm],rs[maxm],cnt[maxm],rt[maxn];
    int fa[maxn],ch[maxn][2],rev[maxn],val[maxn],mi[maxn];
    struct edge
    {
        int x,y;
    }e[maxn];
    void get(int &l,int &r)
    {
        if(t) l=(l+ans)%m+1,r=(r+ans)%m+1;
        if(l>r) swap(l,r);
    }
    bool check(int x)
    {
        return ch[fa[x]][1]==x;
    }
    bool notroot(int x)
    {
        return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
    }
    void pushup(int x)
    {
        mi[x]=val[x];
        mi[x]=min(mi[x],min(mi[ch[x][0]],mi[ch[x][1]]));
    }
    void pushrev(int x)
    {
        rev[x]^=1,swap(ch[x][0],ch[x][1]);
    }
    void pushdown(int x)
    {
        if(!rev[x]) return;
        pushrev(ch[x][0]),pushrev(ch[x][1]),rev[x]=0;
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=check(x),w=ch[x][k^1];
        if(notroot(y)) ch[z][check(y)]=x;
        ch[x][k^1]=y,ch[y][k]=w;
        if(w) fa[w]=y;
        fa[x]=z,fa[y]=x;
        pushup(y),pushup(x);
    }
    void all(int x)
    {
        if(notroot(x)) all(fa[x]);
        pushdown(x);
    }
    void splay(int x)
    {
        all(x);
        for(int y;notroot(x);rotate(x))
            if(notroot(y=fa[x]))
                rotate(check(x)^check(y)?x:y);
        pushup(x);
    }
    void access(int x)
    {
        for(int y=0;x;y=x,x=fa[x])
            splay(x),ch[x][1]=y,pushup(x);
    }
    void makeroot(int x)
    {
        access(x),splay(x),pushrev(x);
    }
    void split(int x,int y)
    {
        makeroot(x),access(y),splay(y);
    }
    int findroot(int x)
    {
        access(x),splay(x);
        while(ch[x][0]) x=ch[x][0];
        splay(x);
        return x;
    }
    void link(int x,int y)
    {
    	split(x,y),fa[x]=y;
    }
    void cut(int x,int y)
    {
    	split(x,y),fa[x]=ch[y][0]=0;
    }
    int ask(int x,int y)
    {
        split(x,y);
        return mi[y];
    }
    void modify(int l,int r,int pos,int v,int &cur)
    {
        int x=++tree_cnt;
        ls[x]=ls[cur],rs[x]=rs[cur],cnt[x]=cnt[cur]+v,cur=x;
        if(l==r) return;
        if(pos<=mid) modify(l,mid,pos,v,ls[cur]);
        else modify(mid+1,r,pos,v,rs[cur]);
    }
    int query(int L,int R,int l,int r,int cur)
    {
        if(L<=l&&R>=r) return cnt[cur];
        int v=0;
        if(L<=mid) v+=query(L,R,l,mid,ls[cur]);
        if(R>mid) v+=query(L,R,mid+1,r,rs[cur]);
        return v;
    }
    int main()
    {
        read(n),read(m),read(q),read(t);
        for(int i=0;i<=n;++i) val[i]=mi[i]=inf;   
        for(int i=1;i<=m;++i) read(e[i].x),read(e[i].y),val[i+n]=mi[i+n]=i;
        for(int i=1;i<=m;++i)
        {
            int x=e[i].x,y=e[i].y;
            rt[i]=rt[i-1];
            if(x==y) continue;
            modify(1,m,i,1,rt[i]);
            if(findroot(x)==findroot(y))
            {
                int p=ask(x,y);
                cut(e[p].x,p+n),cut(e[p].y,p+n);
                modify(1,m,p,-1,rt[i]);
            }
            link(x,i+n),link(y,i+n);
        }
        while(q--)
        {
            int l,r;
            read(l),read(r),get(l,r);
            printf("%d
    ",ans=n-query(l,r,1,m,rt[r]));
        }
        return 0;
    }
    
  • 相关阅读:
    短信
    solr测试用的配置
    中文词启动
    配置域
    applicationContext-redis.xml
    Redis端口配置
    springDataRedis 依赖
    FastDFSClient上传图片工具类
    security 页面测试
    PHP图片压缩功能(按比例图片缩放)(转载)
  • 原文地址:https://www.cnblogs.com/lhm-/p/13295516.html
Copyright © 2011-2022 走看看