zoukankan      html  css  js  c++  java
  • 题解 洛谷 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;
    }
    
  • 相关阅读:
    设置android:supportsRtl=&quot;true&quot;无效问题
    使用 Docker/LXC 迅速启动一个桌面系统
    快速部署Python应用:Nginx+uWSGI配置详解
    链表源代码(C语言实现)
    delete
    Linux与Unix shell编程指南(完整高清版).pdf
    数据挖掘python,java
    shops
    如何用Excel打开CSV文件
    svn迁移到git
  • 原文地址:https://www.cnblogs.com/lhm-/p/13466324.html
Copyright © 2011-2022 走看看