题目:https://loj.ac/problem/2979

原来的思路:

  优化连边。一看就是同一个桌子相邻座位之间连边、相邻桌子对应座位之间连边。

  每个座位向它所属的桌子连边。然后每个人建一个点,向若干桌子连边。

  因为连边的桌子是区间,所以线段树优化。

  又想到志愿者招募之类的,所以想弄一个上下界费用流。人向它的座位连下界为1的边,对应桌子区间向人连边。找一些循环流。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mn(int a,int b){return a<b?a:b;}
const int N=,M=,N2=,M2=,INF=;
int n,m,S,T,L[N][M],R[N][M],dy[N],bh[N][M],tot,Ls[N<<],Rs[N<<];
int rd[N2],hd[N2],xnt=,to[M2],nxt[M2],cap[M2],w[M2];
int ans,dis[N2],pr[N2],info[N2]; bool ins[N2];
queue<int> q;
void add(int x,int y,int l,int r,int z)
{
rd[y]+=l; rd[x]-=l; ans+=l*z; r-=l;
to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=r;w[xnt]=z;
to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=;w[xnt]=-z;
}
void build(int l,int r,int cr)
{
if(l==r){dy[l]=cr;return;}
int mid=l+r>>;
ls=++tot; build(l,mid,ls);
rs=++tot; build(mid+,r,rs);
add(ls,cr,,INF,); add(rs,cr,,INF,);
}
void qry(int l,int r,int cr,int L,int R,int k)
{
if(l>=L&&r<=R)
{
printf("(%d->%d)\n",cr,k);
add(cr,k,,,);return;
}
int mid=l+r>>;
if(L<=mid)qry(l,mid,ls,L,R,k);
if(mid<R)qry(mid+,r,rs,L,R,k);
}
bool spfa()
{
memset(dis,0x3f,sizeof dis); info[T]=;
dis[S]=; info[S]=INF; q.push(S); ins[S]=;
while(q.size())
{
int k=q.front(); q.pop(); ins[k]=;
for(int i=hd[k],v;i;i=nxt[i])
if(cap[i]&&dis[v=to[i]]>dis[k]+w[i])
{
dis[v]=dis[k]+w[i];
pr[v]=i; info[v]=Mn(info[k],cap[i]);
if(!ins[v])ins[v]=,q.push(v);
}
}
return info[T];
}
int ek()
{
int tp=info[T];
for(int i=pr[T];i;i=pr[to[i^]])
{
cap[i]-=tp; cap[i^]+=tp;
ans+=w[i]*tp;
printf("%d ",to[i]);
}
puts("");
return tp;
}
int main()
{
n=rdn();m=rdn();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)L[i][j]=rdn()+;//+1
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)R[i][j]=rdn()+;
tot=;build(,n,); int tmp=n*m;
for(int i=;i<=n;i++,puts(""))
for(int j=;j<=m;j++)bh[i][j]=++tot,printf("%d ",tot);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
qry(,n,,L[i][j],R[i][j],bh[i][j]+tmp);
printf("(%d->%d)\n",bh[i][j]+tmp,bh[i][j]);
add(bh[i][j]+tmp,bh[i][j],,,);
printf("(%d->%d)\n",bh[i][j],dy[i]);
add(bh[i][j],dy[i],,,); printf("(%d->%d)[]\n",bh[i][j],bh[i][j==m?:j+]);
add(bh[i][j],bh[i][j==m?:j+],,INF,);
printf("(%d->%d)[]\n",bh[i][j],bh[i][j>?j-:m]);
add(bh[i][j],bh[i][j>?j-:m],,INF,);
if(i<n)
{
printf("(%d->%d)[]\n",bh[i][j],bh[i+][j]);
add(bh[i][j],bh[i+][j],,INF,);
}
}
tot+=tmp; S=tot+; T=tot+; tmp=;
printf("S=%d T=%d\n",S,T);
for(int i=;i<=tot;i++)
if(rd[i]<)add(i,T,,-rd[i],);
else if(rd[i]>)add(S,i,,rd[i],),tmp+=rd[i];
printf("tmp=%d ans=%d\n",tmp,ans);
while(spfa())tmp-=ek();
if(tmp)puts("no solution");
else printf("%d\n",ans);
return ;
}

然后发现过不了样例。这样是不行的。希望的是 “因为自己连向 x 座位、 y 桌子向自己连边,所以 x 座位到 y 桌子走了一条路” , 但实际上这样相当于自己给 x 座位一些流量、自己向 y 桌子索求一些流量;如果有另一个人,给 y 桌子某座位一些流量、向 x 座位所在桌子索求流量,那么 x 和 y 之间本应有两条路,现在一条也没有了。

正解和这个类似?

每种座位都建两棵线段树,维护所有桌子,一棵表示向左走,一棵表示向右走;即一共 2*m 棵线段树。

然后每个人向线段树对应节点连边;线段树叶子就表示座位;同一个桌子的座位之间连边即可。

向左走的线段树,从自己到左孩子连的边,费用需要加上 “跨过右孩子” 的代价。即到达向左走的线段树某节点,默认当前在该区间的右端点。所以每个人向区间连的 log 条边要注意一下初始费用。

需要多路增广费用流才能过。多路增广,就是 spfa 一次之后,根据 dis[ cr ] 和 dis[ v ] 的关系,像 dinic 一样走。 dinic 的优化都可以加(似乎一定要加当前弧优化?),注意要像 dfs 一样打 vis 标记,因为 dis 上可能有 0 环。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mn(int a,int b){return a<b?a:b;}
int Mx(int a,int b){return a>b?a:b;}
const int N=,M=,INF=;
int n,m,S,T,L[][],R[][],bh[][];
int tot,Ls[N],Rs[N],hd[N],xnt=,to[M],nxt[M],cap[M],w[M];
int ans,mxflow,dis[N],pr[N],info[N]; bool ins[N];
int cur[N];bool vis[N];
queue<int> q;
void add(int x,int y,int c,int z)
{
to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=c;w[xnt]=z;
to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=;w[xnt]=-z;
}
void build(int l,int r,int cr,bool fx,int k)
{
if(l==r)
{
if(!fx)bh[l][k]=++tot;
add(cr,bh[l][k],INF,); return;
}
int mid=l+r>>;
ls=++tot; build(l,mid,ls,fx,k);
rs=++tot; build(mid+,r,rs,fx,k);
if(fx)
{ add(cr,ls,INF,); add(cr,rs,INF,(mid-l+)*);}
else
{ add(cr,ls,INF,(r-mid)*); add(cr,rs,INF,);}
}
void qry(int l,int r,int cr,int L,int R,int lj,bool fx)
{
if(l>=L&&r<=R){ add(tot,cr,,lj);return;}
int mid=l+r>>;
if(!fx)
{
if(L<=mid)qry(l,mid,ls,L,R,lj+*(r-mid),fx);
if(mid<R)qry(mid+,r,rs,L,R,lj,fx);
}
else
{
if(L<=mid)qry(l,mid,ls,L,R,lj,fx);
if(mid<R)qry(mid+,r,rs,L,R,lj+*(mid-l+),fx);
}
}
bool spfa()
{
memset(dis,0x3f,sizeof dis); info[T]=;
dis[S]=; info[S]=INF; q.push(S); ins[S]=;
while(q.size())
{
int k=q.front(); q.pop(); ins[k]=;
for(int i=hd[k],v;i;i=nxt[i])
if(cap[i]&&dis[v=to[i]]>dis[k]+w[i])
{
dis[v]=dis[k]+w[i];
pr[v]=i; info[v]=Mn(info[k],cap[i]);
if(!ins[v])ins[v]=,q.push(v);
}
}
return info[T];
}
int dfs(int cr,int flow)
{
if(cr==T)return flow;
int use=; vis[cr]=;
for(int &i=cur[cr],v;i;i=nxt[i])
if(cap[i]&&!vis[v=to[i]]&&dis[v]==dis[cr]+w[i])
{
int tmp=dfs(v,Mn(flow-use,cap[i]));
if(!tmp)dis[v]=-;
cap[i]-=tmp; cap[i^]+=tmp; ans+=tmp*w[i];
use+=tmp; if(use==flow){vis[cr]=;return use;}
}
vis[cr]=; return use;
}
void solve()
{
int tmp;
while(spfa())
{
memcpy(cur,hd,sizeof hd);
while(tmp=dfs(S,INF))mxflow+=tmp;
}
}
int main()
{
n=rdn();m=rdn();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) L[i][j]=rdn()+;//+1
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) R[i][j]=rdn()+;
tot=*m;
for(int i=;i<=m;i++)
{ build(,n,i,,i); build(,n,i+m,,i);}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{ add(bh[i][j],bh[i][j==m?:j+],INF,);
add(bh[i][j],bh[i][j==?m:j-],INF,);}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
tot++;
if(L[i][j]<i)
qry(,n,j,L[i][j],Mn(i-,R[i][j]),-*(n-i),);
if(R[i][j]>=i)
qry(,n,j+m,Mx(L[i][j],i),R[i][j],-*(i-),);
}
S=tot+; T=tot+;
for(int i=tot-n*m+;i<=tot;i++)add(S,i,,);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)add(bh[i][j],T,,);
solve();
if(mxflow<n*m)puts("no solution");
else printf("%d\n",ans);
return ;
}

LOJ 2979 「THUSCH 2017」换桌——多路增广费用流的更多相关文章

  1. @loj - 2977@ 「THUSCH 2017」巧克力

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 「人生就像一盒巧克力,你永远不知道吃到的下一块是什么味道.」 明 ...

  2. LOJ #2978「THUSCH 2017」杜老师

    听说LOJ传了THUSC题赶紧上去看一波 随便点了一题都不会做想了好久才会写暴力爆了一发过了... LOJ #2978 题意 $ T$次询问,每次询问$ L,R$,问有多少种选取区间中数的方案使得选出 ...

  3. LOJ 2980 「THUSCH 2017」大魔法师——线段树

    题目:https://loj.ac/problem/2980 线段树维护矩阵. 然后是 30 分.似乎是被卡常了?…… #include<cstdio> #include<cstri ...

  4. LOJ 2978 「THUSCH 2017」杜老师——bitset+线性基+结论

    题目:https://loj.ac/problem/2978 题解:https://www.cnblogs.com/Paul-Guderian/p/10248782.html 第 i 个数的 bits ...

  5. LOJ 2997 「THUSCH 2017」巧克力——思路+随机化+斯坦纳树

    题目:https://loj.ac/problem/2977 想到斯坦纳树.但以为只能做 “包含一些点” 而不是 “包含一些颜色” .而且不太会处理中位数. 其实 “包含一些颜色” 用斯坦纳树做也和普 ...

  6. loj#2978. 「THUSCH 2017」杜老师(乱搞)

    题面 传送门 题解 感谢yx巨巨 如果一个数是完全平方数,那么它的所有质因子个数都是偶数 我们把每一个数分别维护它的每一个质因子的奇偶性,那么就是要我们选出若干个数使得所有质因子的个数为偶数.如果用线 ...

  7. LOJ#2977. 「THUSCH 2017」巧克力(斯坦纳树+随机化)

    题目 题目 做法 考虑部分数据(颜色较少)的: 二分中位数\(mid\),将\(v[i]=1000+(v[i]>mid)\) 具体二分操作:然后求出包含\(K\)种颜色的联通快最小的权值和,判断 ...

  8. 「THUSCH 2017」大魔法师 解题报告

    「THUSCH 2017」大魔法师 狗体面太长,帖链接了 思路,维护一个\(1\times 4\)的答案向量表示\(A,B,C,len\),最后一个表示线段树上区间长度,然后每次的操作都有一个转移矩阵 ...

  9. LOJ 2288「THUWC 2017」大葱的神力

    LOJ 2288「THUWC 2017」大葱的神力 Link Solution 比较水的提交答案题了吧 第一个点爆搜 第二个点爆搜+剪枝,我的剪枝就是先算出 \(mx[i]\) 表示选取第 \(i \ ...

随机推荐

  1. ECMAScript 2015 迭代器协议:实现自定义迭代器

    迭代器协议定义了一种标准的方式来产生一个有限或无限序列的值,并且当所有的值都已经被迭代后,就会有一个默认的返回值. 当一个对象只有满足下述条件才会被认为是一个迭代器:它实现了一个 next() 的方法 ...

  2. 网络流强化-HDU2732

    第一次遇到加了“多余”的边会导致WA的——在我看来是很多余,见代码191行 之后会思考为什么,想出来再更. 问题弄明白了,如果你在连接边连了一条到没有柱子的点的边,这个没有柱子的点是不可能连到终点的, ...

  3. python3.7.0 安装与配置

    python 3.7.0 X64下载地址: https://www.python.org/ftp/python/3.7.0/python-3.7.0-amd64.exe 更多版本下载请移步到:http ...

  4. JavaScript.InjectedScriptHost

    "use strict"; (function(InjectedScriptHost, inspectedGlobalObject, injectedScriptId) {     ...

  5. mybatis开发注意事项:字段名称以及表名

    在使用mybatis开发中,数据库设计的时候字段名称最好不要带下划线,推荐使用驼峰命名法 数据表的名称第一个字母大写

  6. CentOS安装ruby, Haskall,io语言

    安装ruby yum install ruby irb rdoc 安装Haskall yum install ghc 安装io语言 安装io语言,需要先安装cmake不过不要使用yum来进行安装,yu ...

  7. telnet访问出现telnet:Unable to connect to remote host: No route to host

    Linux下的防火墙默认是不允许telnet服务通过的,所以,当防火墙不允许telnet服务通过时就会出现上面的这种情况,可以将防火墙关闭或者勾选允许telnet服务即可解决如上的问题.

  8. 问题 1436: 地宫取宝 (dp)

    题目传送门 时间限制: 1Sec 内存限制: 128MB 提交: 423 解决: 94 题目描述 X  国王有一个地宫宝库.是  n  x  m  个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标 ...

  9. 无法删除VMware旧版本,请与技术小组联系

    问题:把文件夹清理了n遍,却无法重装VMware,报错如标题. 原因:相关注册表没删完. 解决办法: - 1.创建一个.txt文本 - 2.将下面的内容复制到.txt文本中: echo off cls ...

  10. 使用WakeLock将Android应用程序保持后台唤醒

    前言: 一些手机app(如微信.QQ等)有新消息来到达,手机屏幕即使在锁屏状态下也会亮起,并提示用户有新消息.但是,一般情况下手机锁屏后,Android系统为了省电以及减少CPU消耗,在一段时间后会使 ...