生死游戏

生死游戏

模拟赛题目,被我放到了cogs上面。

 

写了这道题目之后发现我之前写的二维st表有点蠢...初始化的时候只用两个元素更新即可,而不需要用4个...其中一维为0的情况也没必要单独拿出来写,可以写到一个循环里面...

orz dinic 20w的点,200w的边,秒出。

首先可以看出是最小割的题目,考虑如何建边。对于矩阵中的每一个点,我们由S向其连一条边,流量为b,再由其向T连一条边,流量为w。统计出所有的w和b的和ans,用ans-最大流即为不考虑奇怪的要求的情况下的答案是多少。如果割b,意味着这个人活着。我们可以先将所有奇怪的要求给的钱加进ans,再对于每一个奇怪的要求都开一个新节点,并向其对应矩阵节点连边,如果这个奇怪的要求是想让这些人死掉,那么就S->该节点->矩阵中节点。不然就矩阵中节点->该节点->T。流量的话,与S或T相连的流量为其钱数,与矩阵中节点相连的流量为INF。

然而我们发现边数太多了,需要优化。于是可以利用二维rmq,这样每个奇怪的要求就由nm条边变为了4条边。虽然边数还是很多,然而能过...还挺快...玄学复杂度

  1 /*GHB is best!*/
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 
  6 using namespace std;
  7 void rd(int &x){
  8  x=0;int f=1;char ch=getchar();
  9  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 10  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();
 11  x*=f;
 12 }
 13 
 14 const int INF=1<<30;
 15 
 16 int ans;
 17 int n,m,q;
 18 int b[55][55],w[55][55];
 19 int tot=-1,fi[240000],nxt[2000000],to[2000000],flow[2000000];
 20 void link(int x,int y,int fl){
 21  to[++tot]=y;nxt[tot]=fi[x];fi[x]=tot;flow[tot]=fl;
 22  to[++tot]=x;nxt[tot]=fi[y];fi[y]=tot;flow[tot]=0;
 23 }
 24 int S,T;
 25 int cnt,num[55][55],num2[55][55][7][7][2];//rmp数组要开两倍,一种是与连向T的询问相连,一种是与连向S的询问相连 
 26 int h[55];
 27 
 28 int que[240000],l,r,cur[240000],dep[240000];
 29 bool bfs(){
 30     for(int i=S;i<=T;i++)cur[i]=fi[i],dep[i]=-1;
 31  l=1;r=0;
 32  que[++r]=S;
 33  dep[S]=0;
 34  while(l<=r){
 35   int u=que[l++];
 36   for(int i=fi[u];i!=-1;i=nxt[i])
 37    if(flow[i] && dep[to[i]]==-1){
 38        dep[to[i]]=dep[u]+1;
 39        que[++r]=to[i];
 40    }
 41     }
 42     return dep[T]!=-1;
 43 }
 44 
 45 int dfs(int x,int f){
 46  if(x==T)return f;
 47  for(int i=cur[x];i!=-1;i=nxt[i]){
 48   cur[x]=i;
 49   if(flow[i] && dep[to[i]]==dep[x]+1){
 50    int g=dfs(to[i],min(f,flow[i]));
 51    if(g){
 52     flow[i]-=g;
 53     flow[i^1]+=g;
 54     return g;
 55             }
 56         }
 57     }
 58     return 0;
 59 }
 60 
 61 int main(){
 62     freopen("1675.in","r",stdin);
 63     freopen("1675.out","w",stdout);
 64     memset(fi,-1,sizeof(fi));
 65     rd(n);rd(m);rd(q);
 66     h[0]=-1;
 67     for(int i=1;i<=max(n,m);i++)h[i]=h[i>>1]+1;
 68     for(int i=1;i<=n;i++)
 69      for(int j=1;j<=m;j++)
 70       rd(b[i][j]),ans+=b[i][j];
 71     for(int i=1;i<=n;i++)
 72      for(int j=1;j<=m;j++)
 73       rd(w[i][j]),ans+=w[i][j];
 74     for(int i=1;i<=n;i++)
 75      for(int j=1;j<=m;j++)
 76       num[i][j]=++cnt,num2[i][j][0][0][0]=num2[i][j][0][0][1]=cnt;
 77     for(int i=0;(1<<i)<=n;i++)
 78      for(int j=0;(1<<j)<=m;j++)
 79       if(i+j)
 80        for(int x=1;x+(1<<i)-1<=n;x++)
 81         for(int y=1;y+(1<<j)-1<=m;y++){
 82          num2[x][y][i][j][0]=++cnt;
 83          num2[x][y][i][j][1]=++cnt;
 84                  }
 85     S=0;T=cnt+q+1;
 86     for(int i=1;i<=n;i++)
 87      for(int j=1;j<=m;j++)
 88       link(S,num[i][j],b[i][j]),
 89             link(num[i][j],T,w[i][j]);
 90     for(int i=0;(1<<i)<=n;i++)
 91      for(int j=0;(1<<j)<=m;j++)
 92       if(i+j)
 93              for(int x=1;x+(1<<i)-1<=n;x++)
 94         for(int y=1;y+(1<<j)-1<=m;y++){
 95          if(i)link(num2[x][y][i][j][0],num2[x][y][i-1][j][0],INF),link(num2[x][y][i][j][0],num2[x+(1<<i-1)][y][i-1][j][0],INF);
 96          else link(num2[x][y][i][j][0],num2[x][y][i][j-1][0],INF),link(num2[x][y][i][j][0],num2[x][y+(1<<j-1)][i][j-1][0],INF);
 97                   if(i)link(num2[x][y][i-1][j][1],num2[x][y][i][j][1],INF),link(num2[x+(1<<i-1)][y][i-1][j][1],num2[x][y][i][j][1],INF);
 98                   else link(num2[x][y][i][j-1][1],num2[x][y][i][j][1],INF),link(num2[x][y+(1<<j-1)][i][j-1][1],num2[x][y][i][j][1],INF);
 99                     }
100     for(int i=1;i<=q;i++){
101      int lx,rx,ly,ry,t,s;
102      rd(lx);rd(ly);rd(rx);rd(ry);rd(t);rd(s);
103      ans+=s;
104         int u=h[rx-lx+1],v=h[ry-ly+1];
105      if(t){//
106       link(S,cnt+i,s);
107       link(cnt+i,num2[lx][ly][u][v][0],INF);
108       link(cnt+i,num2[lx][ry-(1<<v)+1][u][v][0],INF);
109       link(cnt+i,num2[rx-(1<<u)+1][ly][u][v][0],INF);
110       link(cnt+i,num2[rx-(1<<u)+1][ry-(1<<v)+1][u][v][0],INF);
111      }
112      else {
113          link(cnt+i,T,s);
114       link(num2[lx][ly][u][v][1],cnt+i,INF);
115       link(num2[lx][ry-(1<<v)+1][u][v][1],cnt+i,INF);
116       link(num2[rx-(1<<u)+1][ly][u][v][1],cnt+i,INF);
117       link(num2[rx-(1<<u)+1][ry-(1<<v)+1][u][v][1],cnt+i,INF);
118      }
119     }
120     int f;
121     while(bfs())
122      while(f=dfs(S,INF))ans-=f;
123     printf("%d\n",ans);
124  return 0;
125 }
View Code

 

转载于:https://www.cnblogs.com/hyghb/p/8869262.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值