• 题解 洛谷 P4230 【连环病原体】


    用双指针扫描来找环,加入 (r) 位置的边后,若形成了环,就删去 (l) 位置的边,直到环断掉,加边删边和判定连通性用 (LCT) 维护即可。

    考虑如何计算环的贡献,对于区间 ([l,r]),若其形成了环,则区间 ([l,r+1],[l,r+2] dots [l,m]) 都形成了环。得最终的贡献为区间 ([l,r]) 都加上 (m-r+1),区间 ([r+1,m]) 加上一个首项为 (m-r),公差为 (-1) 的等差数列。用线段树维护差分数列即可。

    #include<bits/stdc++.h>
    #define maxn 200010
    #define maxm 800010
    #define ls (cur<<1)
    #define rs (cur<<1|1)
    #define mid ((l+r)>>1)
    using namespace std;
    typedef long long ll;
    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 m,root=1,pos=1;
    int fa[maxn],ch[maxn][2],rev[maxn];
    ll sum[maxm],add[maxm],ans[maxn];
    struct edge
    {
        int x,y;
    }e[maxn];
    void pushadd(int cur,int l,int r,ll v)
    {
        sum[cur]+=v*(r-l+1),add[cur]+=v;
    }
    void pushdown(int cur,int l,int r)
    {
        if(!add[cur]) return;
        pushadd(ls,l,mid,add[cur]),pushadd(rs,mid+1,r,add[cur]),add[cur]=0;
    }
    void modify(int L,int R,int l,int r,ll v,int cur)
    {
        if(L>R) return;
        if(L<=l&&R>=r)
        {
            pushadd(cur,l,r,v);
            return;
        }
        pushdown(cur,l,r);
        if(L<=mid) modify(L,R,l,mid,v,ls);
        if(R>mid) modify(L,R,mid+1,r,v,rs);
        sum[cur]=sum[ls]+sum[rs];
    }
    void dfs(int l,int r,int cur)
    {
        if(l==r)
        {
            ans[l]=sum[cur];
            return;
        }
        pushdown(cur,l,r);
        dfs(l,mid,ls),dfs(mid+1,r,rs);
    }
    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 pushrev(int x)
    {
        rev[x]^=1,swap(ch[x][0],ch[x][1]);
    }
    void spread(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;
    }
    void all(int x)
    {
        if(notroot(x)) all(fa[x]);
        spread(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);
    }
    void access(int x)
    {
        for(int y=0;x;y=x,x=fa[x]) splay(x),ch[x][1]=y;
    }
    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 main()
    {
        read(m);
        for(int i=1;i<=m;++i) read(e[i].x),read(e[i].y);
        for(int i=1;i<=m;++i)
        {
            int x=e[i].x,y=e[i].y;
            while(findroot(x)==findroot(y))
            {
                modify(pos,pos,1,m,m-i+1,root);
                modify(i+1,m,1,m,-1,root);
                cut(e[pos].x,e[pos].y),pos++;
            }
            link(x,y);
        }
        dfs(1,m,root);
        for(int i=1;i<=m;++i)
            ans[i]+=ans[i-1],printf("%lld ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    揭秘!阿里实时数仓分布式事务Scale Out设计
    ElementUI中使用el-time-picker向SpringBoot传输24小时制时间参数以及数据库中怎样存储
    Vue中实现清空数组和清空el-table
    Vue中foreach数组与js中遍历数组的写法
    Vue中向js中传递参数并在js中定义对象并转换参数
    若依管理系统导出Excel时添加没有的列和关联码表显示中文进行导出
    MyBatis中传递数组参数和List参数时if-test判空和判断长度的写法
    ElementUI中显示是否以及SpringBoot中怎样存储实体类属性和数据库怎样设计字段
    ElementUI中的el-form怎样格式化显示1和0为是和否
    Vue中通过Axios向SpringBoot发送get和post请求
  • 原文地址:https://www.cnblogs.com/lhm-/p/13466324.html
Copyright © 2020-2023  润新知