• bzoj3218 a+b Problem(最小割+主席树优化建边)


    由于6.22博主要学测,大半时间学文化课,近期刷题量&写题解的数量会急剧下降。

    这题出得挺经典的,首先一眼最小割,考虑朴素的做法:与S联通表示白色,与T联通表示黑色,S向i连流量为w[i]的边,i向T连流量为b[i]的边,然后i'向i连容量为p[i]的边,所有满足条件的j向i'连一条容量为无穷大的边(只要满足其一就要割掉)。然后边数显然不合法,一眼线段树优化,然而发现线段树无法连边,考虑主席树连边,对原序列建主席树,每个点的区间对应主席树上的O(logn)个节点,然后连接容量为无穷大的边即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+7,M=1e6+7,inf=1e9;
    struct edge{int x,id;}e[N];
    int n,m,ecnt,tot,T,ans,mx;
    int L[N],R[N],val[N],seq[N],hd[N],v[M],w[M],nxt[M],q[N],lv[N],lc[N],rc[N],root[N],cnt[N];
    void adde(int x,int y,int z)
    {
        v[++ecnt]=y,w[ecnt]=z,nxt[ecnt]=hd[x],hd[x]=ecnt;
        v[++ecnt]=x,w[ecnt]=0,nxt[ecnt]=hd[y],hd[y]=ecnt;
    }
    int findl(int x)
    {
        int l=1,r=mx,ans=mx;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(seq[mid]>=x)ans=mid,r=mid-1;else l=mid+1;
        }
        return ans;
    }
    int findr(int x)
    {
        int l=1,r=mx,ans=1;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(seq[mid]<=x)ans=mid,l=mid+1;else r=mid-1;
        }
        return ans;
    }
    int update(int prt,int l,int r,int i)
    {
        int rt=++tot;
        if(l==r)lc[rt]=rc[rt]=0,cnt[rt]=cnt[prt]+1;
        else{
            int mid=l+r>>1;
            if(val[i]<=mid)lc[rt]=update(lc[prt],l,mid,i),rc[rt]=rc[prt];
            else rc[rt]=update(rc[prt],mid+1,r,i),lc[rt]=lc[prt];
            cnt[rt]=cnt[lc[rt]]+cnt[rc[rt]];
        }
        adde(i,2*n+1+rt,inf);
        adde(2*n+1+prt,2*n+1+rt,inf);
        return rt;
    }
    void query(int rt,int l,int r,int i)
    {
        if(!cnt[rt])return;
        if(L[i]<=l&&r<=R[i]){adde(2*n+1+rt,n+i,inf);return;}
        int mid=l+r>>1;
        if(L[i]<=mid)query(lc[rt],l,mid,i);
        if(R[i]>mid)query(rc[rt],mid+1,r,i);
    }
    bool bfs()
    {
        memset(lv,-1,sizeof lv);
        int qs=0,qe=1;
        q[0]=lv[0]=0;
        while(qs<qe)
        {
            int u=q[qs++];
            for(int i=hd[u];i;i=nxt[i])if(w[i]&&lv[v[i]]==-1)lv[v[i]]=lv[u]+1,q[qe++]=v[i];
        }
        if(lv[T]==-1)return 0;
        return 1;
    }
    int dfs(int u,int low)
    {
        if(u==T||!low)return low;
        int sum=0;
        for(int i=hd[u];i;i=nxt[i])
        if(w[i]&&lv[v[i]]==lv[u]+1)
        {
            int tmp=dfs(v[i],min(low,w[i]));
            w[i]-=tmp,w[i^1]+=tmp,low-=tmp,sum+=tmp;
            if(!low)return sum;
        }
        if(low)lv[u]=-1;
        return sum;
    }
    bool cmp(edge x,edge y){return x.x<y.x;}
    int main()
    {
        scanf("%d",&n);
        ecnt=1,T=1e5;
        for(int i=1,b,w,p;i<=n;i++)
        {
            scanf("%d%d%d%d%d%d",&e[i].x,&b,&w,&L[i],&R[i],&p);
            e[i].id=i,ans+=b+w,adde(0,i,w),adde(i,T,b),adde(n+i,i,p);
        }
        sort(e+1,e+n+1,cmp);
        mx=val[e[1].id]=1,seq[1]=e[1].x;
        for(int i=2;i<=n;i++)
        if(e[i].x==e[i-1].x)val[e[i].id]=mx;else val[e[i].id]=++mx,seq[mx]=e[i].x;
        for(int i=1;i<=n;i++)
        {
            L[i]=findl(L[i]),R[i]=findr(R[i]);
            root[i]=update(root[i-1],1,mx,i),query(root[i-1],1,mx,i);
        }
        while(bfs())ans-=dfs(0,inf);
        printf("%d",ans);
    }
    View Code
  • 相关阅读:
    HTTP协议
    php目录操作
    PHP有关类的相关知识
    PHP设计模式
    PHP类的继承
    PHP重写
    php类中成员
    php面向对象
    什么是SVN
    ThinkPHP5 初识路由
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10952258.html
Copyright © 2020-2023  润新知