bzoj4200 [Noi2015]小园丁与老司机(dp+记录路径+有源汇有上下界最小流)

这题。。。连想带写一整天gg
首先第一问,是个dp,先把所有点按y为第一关键字,x为第二关键字,从小到大排序,我们把所有y相等的点叫做一层。则一层一层的dp,隔层之间转移可以直接O(1)转移(每个点只能从最多三个点上来),层内可以 O(n2) O ( n 2 ) 转移(如果不要求记录路径的话,可以做到O(n))。同层怎么转移呢?首先我们有刚进入这一层时各个点的最优值,现在我们要求出从这一层出去的每个点的最优值,可以发现如果我们要求从i出去的最优值,则我们只需枚举一个进入这层的j点,就可以转移了。(i左边的点随便选一个进入,都可以先走到最左端,然后再走回i,所以可以遍历i左边的所有点,右边同理,别忘了还有自己。)然后我们输出一条合法路径就好了。
现在求第二问,就是从dp值为ans的所有点遍历所有的最优决策点,根据决策建边。然后要求用最少的路径数覆盖所有边。可以直接用有上下界的最小流解决,做法见:bzoj2502
还可以有个小优化:跑最小流时第二遍的结果一定是满流的,所以可以只跑第一遍,然后用满流-第一遍的最大流就是答案。至于路径怎么记录,可以详见代码。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 50010
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,lsy[N],lsx[N],ls1[N],ls2[N],ny=0,nx=0,n1=0,n2=0,last1[N],last2[N],lastx[N];
int yl[N],yr[N],path[N][4],dp[N],h[N],num=1,s=50001,t=50002,T=50003,S=50004,out[N];
int cur[N],lev[N],in[N];
vector<int>best[N];
bool vis[N];
struct Point{
    int x,y,id,k1,k2;
}p[N];
struct edge{
    int to,next,val;
}data[N*20];
inline bool cmp(Point x,Point y){return x.y==y.y?x.x<y.x:x.y<y.y;}
inline int abs(int x){return x<0?-x:x;}
inline void add(int x,int y,int val){
    data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;
    data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].val=0;
}
inline void work(int l,int r){
    int mx[5100],mx1[5100],tmp[5100];
    memset(mx,0,sizeof(mx));memset(mx1,0,sizeof(mx1));
    for(int i=l;i<=r;++i) tmp[i-l+1]=dp[i];
    for(int i=l;i<=r;++i) mx[i-l+1]=max(dp[i],mx[i-l+1-1]);
    for(int i=r;i>=l;--i) mx1[i-l+1]=max(dp[i],mx1[i-l+1+1]);
    for(int i=l;i<=r;++i){
        if(mx[i-l+1-1]!=0) dp[i]=max(dp[i],i-l+mx[i-l+1-1]);
        if(mx1[i-l+1+1]!=0) dp[i]=max(dp[i],r-i+mx1[i-l+1+1]);
    }for(int i=l;i<=r;++i){
        for(int j=l;j<i;++j)
            if(tmp[j-l+1]!=-1&&i-l+tmp[j-l+1]==dp[i]) best[i].push_back(j);
        for(int j=i+1;j<=r;++j)
            if(tmp[j-l+1]!=-1&&r-i+tmp[j-l+1]==dp[i]) best[i].push_back(j);
        if(tmp[i-l+1]!=-1&&tmp[i-l+1]==dp[i]) best[i].push_back(i);
    }
}
inline void dfs(int x){
    if(x==0) return;
    int y=best[x][0];
    dfs(path[y][1]);
    if(y==x){printf("%d ",p[x].id);return;}
    if(y<x){
        for(int i=y;i>=yl[p[x].y];--i) printf("%d ",p[i].id);
        for(int i=y+1;i<=x;++i) printf("%d ",p[i].id);return;
    }
    for(int i=y;i<=yr[p[x].y];++i) printf("%d ",p[i].id);
    for(int i=y-1;i>=x;--i) printf("%d ",p[i].id);return;
}
inline void dfs1(int x){
    if(x==0) return;
    for(int i=0;i<best[x].size();++i){
        int y=best[x][i];if(vis[y]) continue;vis[y]=1;
        for(int i=1;i<=path[y][0];++i){
            add(path[y][i],y,inf);out[path[y][i]]++;
            in[y]++;in[path[y][i]]--;dfs1(path[y][i]);
        }
    }
}
inline bool bfs(){
    queue<int>q;memset(lev,0,sizeof(lev));
    lev[S]=1;q.push(S);
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=h[x];i;i=data[i].next){
            int y=data[i].to;if(lev[y]||!data[i].val) continue;
            lev[y]=lev[x]+1;q.push(y);
        }   
    }return lev[T];
}
inline int dinic(int x,int low){
    if(x==T) return low;int tmp=low;
    for(int &i=cur[x];i;i=data[i].next){
        int y=data[i].to;if(lev[y]!=lev[x]+1||!data[i].val) continue;
        int res=dinic(y,min(tmp,data[i].val));
        if(!res) lev[y]=0;else tmp-=res,data[i].val-=res,data[i^1].val+=res;
        if(!tmp) return low;
    }return low-tmp;
}
int main(){
//  freopen("a2.in","r",stdin);
//  freopen("a.out","w",stdout);
    n=read();memset(dp,-1,sizeof(dp));
    for(int i=1;i<=n;++i){
        p[i].x=read(),p[i].y=read(),p[i].id=i;lsy[i]=p[i].y;lsx[i]=p[i].x;
        ls1[i]=p[i].k1=p[i].y-p[i].x;ls2[i]=p[i].k2=p[i].y+p[i].x;
    }sort(lsy,lsy+n+1);sort(ls1,ls1+n+1);sort(ls2,ls2+n+1);sort(lsx,lsx+n+1);
    ny=unique(lsy,lsy+n+1)-lsy-1;nx=unique(lsx,lsx+n+1)-lsx-1;
    n1=unique(ls1,ls1+n+1)-ls1-1;n2=unique(ls2,ls2+n+1)-ls2-1;
    for(int i=0;i<=n;++i){
        p[i].k1=lower_bound(ls1,ls1+n1+1,p[i].k1)-ls1;
        p[i].k2=lower_bound(ls2,ls2+n2+1,p[i].k2)-ls2;
        p[i].y=lower_bound(lsy,lsy+ny+1,p[i].y)-lsy;
        p[i].x=lower_bound(lsx,lsx+nx+1,p[i].x)-lsx;
    }sort(p+1,p+n+1,cmp);int last=1;memset(last1,-1,sizeof(last1));
    memset(last2,-1,sizeof(last2));memset(lastx,-1,sizeof(lastx));
    last1[p[0].k1]=last2[p[0].k2]=lastx[p[0].x]=0;
    memset(path,-1,sizeof(path));dp[0]=0;
    for(int i=1;i<=n;++i){
        while(last<=n&&p[last].y==p[i].y){
            Point &a=p[last];int tot=0;
            if(last1[a.k1]!=-1&&dp[last1[a.k1]]!=-1){
                if(dp[last1[a.k1]]+1==dp[last]) path[last][++tot]=last1[a.k1];
                if(dp[last1[a.k1]]+1>dp[last]) dp[last]=dp[last1[a.k1]]+1,tot=0,path[last][++tot]=last1[a.k1];
            }last1[a.k1]=last;
            if(last2[a.k2]!=-1&&dp[last2[a.k2]]!=-1){
                if(dp[last2[a.k2]]+1==dp[last]) path[last][++tot]=last2[a.k2];
                if(dp[last2[a.k2]]+1>dp[last]) dp[last]=dp[last2[a.k2]]+1,tot=0,path[last][++tot]=last2[a.k2];
            }last2[a.k2]=last;
            if(lastx[a.x]!=-1&&dp[lastx[a.x]]!=-1){
                if(dp[lastx[a.x]]+1==dp[last]) path[last][++tot]=lastx[a.x];
                if(dp[lastx[a.x]]+1>dp[last]) dp[last]=dp[lastx[a.x]]+1,tot=0,path[last][++tot]=lastx[a.x];
            }lastx[a.x]=last;path[last][0]=tot;++last;
        }last--;yl[p[i].y]=i;yr[p[i].y]=last;
        work(i,last);i=last;last++;
    }int ans=0,tot=0;
    for(int i=1;i<=n;++i) if(dp[i]>dp[ans]) ans=i;
    printf("%d\n",dp[ans]);dfs(ans);puts("");
    for(int i=1;i<=n;++i) if(dp[i]==dp[ans])dfs1(i);ans=0;
    for(int i=0;i<=n;++i){
        add(s,i,inf);if(!out[i]) add(i,t,inf);
        if(in[i]>0) add(S,i,in[i]),tot+=in[i];
        if(in[i]<0) add(i,T,-in[i]);
    }while(bfs()){memcpy(cur,h,sizeof(cur));ans+=dinic(S,inf);}
    printf("%d\n",tot-ans);
    return 0;
}

6.26UPD:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 50010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,nn,to[N][3],aa[N],lst[N],b[N],f[N],path[N][4],g[N],best[N],id[N];//f[i],到点i的最多经过点数
int ss,tt,S=0,T,cur[N],lev[N],in[N],h[N],num=1;bool vis[N];
struct point{
    int x,y,id;
    friend bool operator<(point a,point b){return a.y==b.y?a.x<b.x:a.y<b.y;}
}a[N];
vector<int>path1[N],anss;
struct edge{
    int to,next,val;
}data[N*12];
inline void add(int x,int y,int val){
    data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;
    data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].val=0;
}
inline void solve(int mm){
    int mx=-inf;best[0]=0;
    for(int i=1;i<=mm;++i){
        if(mx+i-1>g[b[i]]){
            g[b[i]]=mx+i-1,path1[b[i]].clear();
            for(int j=1;j<=best[0];++j) path1[b[i]].push_back(best[j]);
        }else if(mx+i-1==g[b[i]]) for(int j=1;j<=best[0];++j) path1[b[i]].push_back(best[j]);
        if(f[b[i]]>mx) mx=f[b[i]],best[best[0]=1]=b[i];
        else if(f[b[i]]==mx) best[++best[0]]=b[i];
    }mx=-inf;best[0]=0;
    for(int i=mm;i>=1;--i){
        if(mx+mm-i>g[b[i]]){
            g[b[i]]=mx+mm-i,path1[b[i]].clear();
            for(int j=1;j<=best[0];++j) path1[b[i]].push_back(best[j]);
        }else if(mx+mm-i==g[b[i]]) for(int j=1;j<=best[0];++j) path1[b[i]].push_back(best[j]);
        if(f[b[i]]>mx) mx=f[b[i]],best[best[0]=1]=b[i];
        else if(f[b[i]]==mx) best[++best[0]]=b[i];
    }for(int i=1;i<=mm;++i){
        if(f[b[i]]>g[b[i]]){
            g[b[i]]=f[b[i]],path1[b[i]].clear();path1[b[i]].push_back(b[i]);
        }else if(f[b[i]]==g[b[i]]) path1[b[i]].push_back(b[i]);
    }for(int i=1;i<=mm;++i) f[b[i]]=g[b[i]];
}
inline void dfs(int x){
    if(x==1) return;
    anss.push_back(x);
    int y=path1[x][0];
    if(id[y]<id[x]){
        int xx=id[x]-1;
        while(xx>id[y]) anss.push_back(a[xx].id),--xx;
        xx=id[y];
        while(a[xx].y==a[id[x]].y) --xx;++xx;
        while(xx<id[y]) anss.push_back(a[xx].id),++xx;
    }if(id[y]>id[x]){
        int xx=id[x]+1;
        while(xx<id[y]) anss.push_back(a[xx].id),++xx;
        xx=id[y];
        while(a[xx].y==a[id[x]].y) ++xx;--xx;
        while(xx>id[y]) anss.push_back(a[xx].id),--xx;
    }if(x!=y) anss.push_back(y);dfs(path[y][1]);
}
inline void dfs1(int x){
    if(x==1) return;
    for(int i=0;i<path1[x].size();++i){
        int y=path1[x][i];if(vis[y]) continue;vis[y]=1;
        for(int j=1;j<=path[y][0];++j) in[y]++,in[path[y][j]]--,add(path[y][j],y,inf),dfs1(path[y][j]);

    }
}
inline bool bfs(){
    queue<int>q;memset(lev,0,sizeof(lev));
    q.push(S);lev[S]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=h[x];i;i=data[i].next){
            int y=data[i].to;if(lev[y]||!data[i].val) continue;
            lev[y]=lev[x]+1;if(y==T) return 1;q.push(y);
        }
    }return 0;
}
inline int dinic(int x,int low){
    if(x==T) return low;int tmp=low;
    for(int &i=cur[x];i;i=data[i].next){
        int y=data[i].to;if(lev[y]!=lev[x]+1||!data[i].val) continue;
        int res=dinic(y,min(tmp,data[i].val));
        if(!res) lev[y]=0;else tmp-=res,data[i].val-=res,data[i^1].val+=res;
        if(!tmp) return low;
    }return low-tmp;
}
int main(){
//  freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);
    n=read()+1;a[1].id=1;a[1].x=0;a[1].y=0;memset(f,-inf,sizeof(f));memset(g,-inf,sizeof(g));
    for(int i=2;i<=n;++i) a[i].id=i,a[i].x=read(),a[i].y=read();f[1]=0;g[1]=0;
    sort(a+1,a+n+1);for(int i=1;i<=n;++i) id[a[i].id]=i;
    for(int i=1;i<=n;++i) aa[i]=a[i].x;
    sort(aa+1,aa+n+1);nn=unique(aa+1,aa+n+1)-aa-1;
    for(int i=1;i<=n;++i){
        int x=lower_bound(aa+1,aa+nn+1,a[i].x)-aa;
        to[lst[x]][0]=a[i].id;lst[x]=a[i].id;
    }for(int i=1;i<=n;++i) aa[i]=a[i].x+a[i].y;
    sort(aa+1,aa+n+1);nn=unique(aa+1,aa+n+1)-aa-1;memset(lst,0,sizeof(lst));
    for(int i=1;i<=n;++i){
        int x=lower_bound(aa+1,aa+nn+1,a[i].x+a[i].y)-aa;
        to[lst[x]][1]=a[i].id;lst[x]=a[i].id;
    }for(int i=1;i<=n;++i) aa[i]=a[i].x-a[i].y;
    sort(aa+1,aa+n+1);nn=unique(aa+1,aa+n+1)-aa-1;memset(lst,0,sizeof(lst));
    for(int i=1;i<=n;++i){
        int x=lower_bound(aa+1,aa+nn+1,a[i].x-a[i].y)-aa;
        to[lst[x]][2]=a[i].id;lst[x]=a[i].id;
    }for(int i=1,j;i<=n;i=j+1){
        j=i;while(j<=n&&a[j].y==a[i].y) ++j;--j;
        for(int k=1;k<=j-i+1;++k) b[k]=a[i+k-1].id;solve(j-i+1);
        for(int k=i;k<=j;++k){
            int x=a[k].id;
            for(int ii=0;ii<3;++ii){
                int y=to[x][ii];if(!y) continue;
                if(f[x]+1>f[y]) f[y]=f[x]+1,path[y][path[y][0]=1]=x;
                else if(f[x]+1==f[y]) path[y][++path[y][0]]=x;
            }
        }
    }int ans=0;for(int i=1;i<=n;++i) ans=max(ans,f[i]);
    printf("%d\n",ans);
    for(int i=1;i<=n;++i) if(f[i]==ans){dfs(i);break;}
    reverse(anss.begin(),anss.end());
    for(int i=0;i<anss.size();++i) printf("%d ",anss[i]-1);puts("");
    for(int i=1;i<=n;++i) if(f[i]==ans) dfs1(i);ss=n+1;tt=n+2;T=n+3;int tot=0;
    for(int i=1;i<=n;++i){
        add(ss,i,inf),add(i,tt,inf);
        if(in[i]>0) add(S,i,in[i]),tot+=in[i];
        else add(i,T,-in[i]);
    }ans=0;while(bfs()){memcpy(cur,h,sizeof(h));ans+=dinic(0,inf);}
    printf("%d\n",tot-ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值