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

猜你喜欢

转载自www.cnblogs.com/hfctf0210/p/10952258.html
今日推荐