生死游戏
模拟赛题目,被我放到了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 #include3 #include 4 #include 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<) 78 for(int j=0;(1< ) 79 if(i+j) 80 for(int x=1;x+(1<1<=n;x++) 81 for(int y=1;y+(1< 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<) 91 for(int j=0;(1< ) 92 if(i+j) 93 for(int x=1;x+(1<1<=n;x++) 94 for(int y=1;y+(1< 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< 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< 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< 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< 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< 1][u][v][0],INF); 109 link(cnt+i,num2[rx-(1<1][ly][u][v][0],INF); 110 link(cnt+i,num2[rx-(1<1][ry-(1< 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< 1][u][v][1],cnt+i,INF); 116 link(num2[rx-(1<1][ly][u][v][1],cnt+i,INF); 117 link(num2[rx-(1<1][ry-(1< 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 }