P3308 [SDOI2014]LIS(最小割+退流)

Posted bztminamoto

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3308 [SDOI2014]LIS(最小割+退流)相关的知识,希望对你有一定的参考价值。

传送门

(f[i])为以(i)结尾的最长上升子序列。可以考虑建这样一张图,对于所有的(i<j,f[j]=f[i+1])连边((i,j))(f[i]=1)的话连边((S,i))(f[i]=max(f[j]))的话连边((j,T)),然后就是删去若干个点使(S,T)不连通并且代价最小,那么拆点最小割就行了

然后是字典序的问题。我们把所有的点按(c)排个序然后看看这个点也就是新图中的这条边是否可以在最小割里。只要判断一下残量网络中是否存在(u)(u+n)的路径就是了

然后删去这条边之后要重新算最大流,如果直接计算会T,这样的话我们可以退流,就是从(T)(u+n)跑一次最大流再从(u)(S)跑一次最大流就可以消除这条边的影响

//minamoto
#include<bits/stdc++.h>
#define R register
#define inf 0x3f3f3f3f
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=1e4+5,M=1e6+5;
struct eg{int v,nx,w;}e[M];int head[N],tot=1;
inline void add(R int u,R int v,R int w){
    e[++tot]={v,head[u],w},head[u]=tot;
    e[++tot]={u,head[v],0},head[v]=tot;
}
struct node{
    int c,id;
    inline bool operator <(const node &b)const{return c<b.c;}
}c[N];
int dep[N],q[N],a[N],b[N],f[N],st[N];
int n,m,mx,S,T,h,t,top,flow;
bool bfs(int S,int T){
    fp(i,0,(n<<1|1))dep[i]=-1;q[h=t=1]=S,dep[S]=0;
    while(h<=t){
        int u=q[h++];go(u)if(dep[v]<0&&e[i].w){
            dep[v]=dep[u]+1,q[++t]=v;
            if(v==T)return true;
        }
    }return false;
}
int dfs(int u,int T,int lim){
    if(u==T||!lim)return lim;int flow=0,f;
    go(u)if(dep[v]==dep[u]+1&&(f=dfs(v,T,min(lim,e[i].w)))){
        flow+=f,lim-=f,e[i].w-=f,e[i^1].w+=f;
        if(!lim)break;
    }if(!flow)dep[u]=-1;return flow;
}
inline int dinic(int S,int T){int flow=0;while(bfs(S,T))flow+=dfs(S,T,inf);return flow;}
inline void cl(){memset(head,0,sizeof(head)),mx=0,tot=1;}
void solve(){
    cl(),n=read();
    fp(i,1,n)a[i]=read();
    fp(i,1,n)b[i]=read();
    fp(i,1,n)c[i].c=read(),c[i].id=i;
    fp(i,1,n){
        f[i]=1;
        fp(j,1,i-1)if(a[j]<a[i])cmax(f[i],f[j]+1);
        cmax(mx,f[i]);
    }S=0,T=n<<1|1,top=0;
    fp(i,1,n)add(i,i+n,b[i]);
    fp(i,1,n)if(f[i]==1)add(S,i,inf);
    fp(i,1,n)if(f[i]==mx)add(i+n,T,inf);
    fp(i,1,n)fp(j,1,i-1)if(a[j]<a[i]&&f[i]==f[j]+1)add(j+n,i,inf);
    flow=dinic(S,T);sort(c+1,c+1+n);
    fp(i,1,n){
        int u=c[i].id;if(bfs(u,u+n))continue;
        dinic(T,u+n),dinic(u,S),st[++top]=u;
    }sort(st+1,st+1+top);printf("%d %d
",flow,top);
    fp(i,1,top)printf("%d%c",st[i]," 
"[i==top]);
}
int main(){
//  freopen("testdata.in","r",stdin);
    int cas=read();
    while(cas--)solve();
    return 0;
}

以上是关于P3308 [SDOI2014]LIS(最小割+退流)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj千题计划141:bzoj3532: [Sdoi2014]Lis

SDOI2014 LIS

[BZOJ3532][SDOI2014]LIS

[SDOI2014]LIS

[题解]SDOI2014LIS

[SDOI2014]LIS