[bzoj3218]a + b Problem

3218: a + b Problem

Time Limit: 20 Sec Memory Limit: 40 MB
Submit: 828 Solved: 289
[Submit][Status][Discuss]

这里写图片描述
这里写图片描述
这道题还是比较好的。
将点拆成i和i’。
从S向i连w[i]的边,从i向T连b[i]的边。
从i’向i连p[i]的边,从i之前符合条件的j向i’连inf的边。
这样的话边的大小是n^2的。
所以我们可以优化一下第四种边,可以用一颗权值线段树,连边是查询l[i],r[i]这段区间,从这段区间直接向i’连inf的边,再从i向a[i]所对应的叶子连inf的边。
但是这样的话就不能保证j < i了。所以需要将权值线段树变成主席树,每次新都新建出一条链来,再从对应的旧的链上的对应节点连过来就行了。

#include<cstdio>
using namespace std;
#include<iostream>
#include<algorithm>
#define T n*2+2
#define inf 0x7fffffff
const int N=100100;
const int M=1000000;
struct S{int st,en,va;}aa[M];
int l[M],r[M],root[M],siz=0;
int n,a[N],b[N],w[N],li[N],ri[N],p[N],ans,all[N*3];
int point[N],next[M],gap[N],dis[N],cur[N],pre[N],tot=1;
inline void add(int x,int y,int z){
    next[++tot]=point[x];point[x]=tot;
    aa[tot].st=x;aa[tot].en=y;aa[tot].va=z;
    next[++tot]=point[y];point[y]=tot;
    aa[tot].st=y;aa[tot].en=x;aa[tot].va=0;
}
inline int ISAP(int ss,int tt){
    bool f;
    int i,y,u,minn,sum=0;
    u=ss;gap[0]=T+siz;
    for(i=1;i<=T+siz;++i) cur[i]=point[i];
    while(dis[ss]<T+siz){
        f=false;
        for(i=cur[u];i;i=next[i])
          if(dis[aa[i].en]+1==dis[u]&&aa[i].va>0){
            f=true;cur[u]=i;break;
          }
        if(f){
            pre[u=aa[i].en]=i;
            if(u==tt){
                minn=inf;
                for(i=u;i!=ss;i=aa[pre[i]].st)
                  minn=min(minn,aa[pre[i]].va);
                for(i=u;i!=ss;i=aa[pre[i]].st){
                    aa[pre[i]].va-=minn;
                    aa[pre[i]^1].va+=minn;
                }
                u=ss;sum+=minn;
            }
        }
        else{
            --gap[dis[u]];
            if(!gap[dis[u]]) return sum;
            y=T+siz;cur[u]=point[u];
            for(i=point[u];i;i=next[i])
              if(aa[i].va>0) y=min(y,dis[aa[i].en]);
            ++gap[dis[u]=y+1];
            if(u!=ss) u=aa[pre[u]].st;  
        }
    }
    return sum;
}
#define mid (L+R)/2
inline void insert(int L,int R,int x,int &y,int z,int to){
    y=++siz;
    add(to,y+T,inf);
    add(x+T,y+T,inf);
    if(L==R){
        return ;
    }
    l[y]=l[x];r[y]=r[x];
    if(z<=mid) insert(L,mid,l[x],l[y],z,to);
    else insert(mid+1,R,r[x],r[y],z,to);
}
inline void query(int L,int R,int now,int x,int y,int to){
    if (!now) return;
    if(x<=L&&y>=R){
        add(T+now,to,inf);
        return ;
    }
    if(x<=mid) query(L,mid,l[now],x,y,to); 
    if(y>mid) query(mid+1,R,r[now],x,y,to);
}
int main(){
    int i,j,size;
    scanf("%d",&n);
    for(i=1;i<=n;++i){
        scanf("%d%d%d%d%d%d",&a[i],&b[i],&w[i],&li[i],&ri[i],&p[i]);
        ans+=b[i]+w[i];
        add(1,i+n+1,w[i]);
        add(i+n+1,T,b[i]);
        add(i+1,i+n+1,p[i]);
        all[++all[0]]=a[i],all[++all[0]]=li[i],all[++all[0]]=ri[i];
    }
    sort(all+1,all+all[0]+1);
    size=unique(all+1,all+all[0]+1)-all-1;
    for(i=1;i<=n;++i){
        a[i]=upper_bound(all+1,all+size+1,a[i])-all-1;
        li[i]=upper_bound(all+1,all+size+1,li[i])-all-1;
        ri[i]=upper_bound(all+1,all+size+1,ri[i])-all-1;
    }
    for(i=1;i<=n;++i){
        insert(1,size,root[i-1],root[i],a[i],i+n+1);
        query(1,size,root[i-1],li[i],ri[i],i+1);
    }
    printf("%d\n",ans-ISAP(1,T));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值