题目描述:
qwq
题目分析:
求最小字典序最小割
如何判断一条边是否是割边是很容易的 只需要从u出发看是否能找到一条u到v的增广路,如果存在这样的一条路径 说明该边不是割边
那么我们按照C的大小来枚举每一条边 如果该边是割边 那么我们就要把它从图中删除(这样可以让一些割边不再是满流的边 这些删除的割边都是一定不与当前割边在同一割集中的割边 要让这样的边不能入选)
那么我们要怎样最快的消除这条边呢?我们使用退流算法 从T到v跑一次最大流 从u到S跑一遍最大流即可消除当前边的影响 再把当前边的容量设置为0
题目链接:
Ac 代码:
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
const int inf=0x7fffffff;
const int maxm=1505;
const int N=2000005;
int head[maxm],cap[N],to[N],net[N];
int cnt=1;
inline void add(int u,int v,int c){cnt++;to[cnt]=v,cap[cnt]=c,net[cnt]=head[u],head[u]=cnt;}
inline void addedge(int u,int v,int c){add(u,v,c),add(v,u,0);}
int deep[maxm];
std::queue<int> dl;
namespace Maxflow{
inline bool BFS(int s,int t)
{
while(!dl.empty()) dl.pop();
memset(deep,-1,sizeof(deep));
dl.push(s),deep[s]=0;
while(!dl.empty())
{
int now=dl.front();
dl.pop();
for(int i=head[now];i;i=net[i])
if(cap[i]>0&&deep[to[i]]==-1)
dl.push(to[i]),deep[to[i]]=deep[now]+1;
}
return deep[t]!=-1;
}
int dfs(int now,int flow,int t)
{
if(now==t) return flow;
int w,used=0;
for(int i=head[now];i;i=net[i])
{
int v=to[i];
if(deep[v]==deep[now]+1&&cap[i])
{
w=dfs(v,std::min(cap[i],flow-used),t);
cap[i]-=w,cap[i^1]+=w;
used+=w;
if(used==flow) return flow;
}
}
if(!used) deep[now]=-1;
return used;
}
int Dinic(int s,int t)
{
int maxflow=0;
while(BFS(s,t)) maxflow+=dfs(s,inf,t);
return maxflow;
}
}
int a[maxm],b[maxm],c[maxm],p[maxm];
int dp[maxm];
int ans[maxm],tot;
int n;
inline int comp(int x,int y){return c[x]<c[y];}
void work()
{
memset(head,0,sizeof(head));
memset(dp,0,sizeof(dp));
cnt=1,tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++) scanf("%d",&c[i]),addedge(i,i+n,b[i]);
for(int i=1;i<=n;i++) p[i]=i;
std::sort(p+1,p+n+1,comp);
int max=0;
for(int i=1;i<=n;i++)
{
dp[i]=1;
for(int j=1;j<i;j++)
if(a[i]>a[j]) dp[i]=std::max(dp[i],dp[j]+1);
max=std::max(max,dp[i]);
}
int s=0,t=2*n+10;
for(int i=1;i<=n;i++) if(dp[i]==max) addedge(i+n,t,inf);
for(int i=1;i<=n;i++) if(dp[i]==1) addedge(s,i,inf);
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
if(a[i]>a[j]&&dp[i]==dp[j]+1) addedge(j+n,i,inf);
printf("%d ",Maxflow::Dinic(s,t));
for(int i=1;i<=n;i++)
{
int x=p[i];
s=x,t=x+n;
if(cap[2*x]||Maxflow::BFS(s,t)) continue;
s=x,t=0;
Maxflow::Dinic(s,t);
s=2*n+10,t=x+n;
Maxflow::Dinic(s,t);
cap[2*x]=cap[2*x+1]=0;
ans[++tot]=x;
}
std::sort(ans+1,ans+tot+1);
printf("%d\n",tot);
for(int i=1;i<=tot;i++)
printf("%d ",ans[i]);
puts("");
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
work();
return 0;
}