1. 程式人生 > >BZOJ5101 POI2018Powódź(並查集)

BZOJ5101 POI2018Powódź(並查集)

  如果某個格子的積水量超過了該格子的某個擋板高度,那麼擋板另一端的積水量就會與其相同。看起來是一個不斷合併的過程,考慮並查集。列舉深度,維護每個連通塊內的方案數,深度超過某擋板高度時,將兩端的連通塊合併,即方案數相乘。再加上該連通塊均為當前深度的這種方案。這樣複雜度即為O(nmHα)或O(n2m2α)。

  注意到每次更新所有連通塊的答案並沒有意義,於是可以進一步優化,對每個連通塊儲存其已被更新到的深度,需要將其合併時再實際更新。複雜度即為O(nmα)。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include
<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 1000010 #define P 1000000007 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return
m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,h,fa[N],ans[N],cur[N],t; struct data { int x,y,z;
bool operator <(const data&a) const { return z<a.z; } }edge[N]; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} int trans(int x,int y){return (x-1)*m+y;} int main() { #ifndef ONLINE_JUDGE freopen("bzoj5101.in","r",stdin); freopen("bzoj5101.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(),h=read(); for (int i=1;i<=n*m;i++) fa[i]=i,ans[i]=1; for (int i=1;i<=n;i++) for (int j=1;j<m;j++) t++,edge[t].x=trans(i,j),edge[t].y=trans(i,j+1),edge[t].z=read(); for (int i=1;i<n;i++) for (int j=1;j<=m;j++) t++,edge[t].x=trans(i,j),edge[t].y=trans(i+1,j),edge[t].z=read(); sort(edge+1,edge+t+1); for (int i=1;i<=t;i++) { int p=find(edge[i].x),q=find(edge[i].y); if (p!=q) { ans[p]+=edge[i].z-cur[p]; ans[q]+=edge[i].z-cur[q]; fa[q]=p;ans[p]=1ll*ans[p]*ans[q]%P;cur[p]=edge[i].z; } } cout<<(ans[find(1)]+h-cur[find(1)])%P; return 0; }