[POI2018]Powódź
题目大意:
一个$n\times m(nm\le5\times10^5)$的网格图,每个格子间有一个给定高度的挡板,每个格子的水位是$0\sim h(h\le10^9)$之间的一个整数。问总共有多少种可能的水位情况。
思路:
建立Kruskal重构树,实点代表原图中的格点,虚点代表若干个格点水位越过挡板进行合并后形成的新连通块。求出每个点所代表连通块的水位最大值$max[i]$和最小值$min[i]$,根结点的$max$值为$h$。进行树形DP。转移方程$f[i]=f[ch[i][0]]\times f[ch[i][1]]+max[i]-min[i]+1$。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 #include<sys/mman.h> 5 #include<sys/stat.h> 6 typedef long long int64; 7 class MMapInput { 8 private: 9 char *buf,*p; 10 int size; 11 public: 12 MMapInput() { 13 register int fd=fileno(stdin); 14 struct stat sb; 15 fstat(fd,&sb); 16 size=sb.st_size; 17 buf=reinterpret_cast<char*>(mmap(0,size,PROT_READ,MAP_PRIVATE,fileno(stdin),0)); 18 p=buf; 19 } 20 char getchar() { 21 return (p==buf+size||*p==EOF)?EOF:*p++; 22 } 23 }; 24 MMapInput mmi; 25 inline int getint() { 26 register char ch; 27 while(!isdigit(ch=mmi.getchar())); 28 register int x=ch^'0'; 29 while(isdigit(ch=mmi.getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 30 return x; 31 } 32 const int N=1e6,mod=1e9+7; 33 int n,m,h,cnt,tot,max[N],min[N],ch[N][2],f[N]; 34 struct Edge { 35 int u,v,w; 36 bool operator < (const Edge &another) const { 37 return w<another.w; 38 } 39 }; 40 Edge e[N]; 41 inline int id(const int &x,const int &y) { 42 return x*m+y+1; 43 } 44 struct DisjointSet { 45 int anc[N]; 46 DisjointSet() { 47 for(register int i=0;i<N;i++) anc[i]=i; 48 } 49 int find(const int &x) { 50 return x==anc[x]?x:anc[x]=find(anc[x]); 51 } 52 void merge(const int &x,const int &y) { 53 anc[find(x)]=find(y); 54 } 55 bool same(const int &x,const int &y) { 56 return find(x)==find(y); 57 } 58 }; 59 DisjointSet s; 60 inline void kruskal() { 61 tot=n*m; 62 std::sort(&e[0],&e[cnt]); 63 for(register int i=0;i<cnt;i++) { 64 const int &u=e[i].u,&v=e[i].v,&w=e[i].w; 65 if(!s.same(u,v)) { 66 min[++tot]=w+1; 67 max[s.find(u)]=max[s.find(v)]=w; 68 ch[tot][0]=s.find(u); 69 ch[tot][1]=s.find(v); 70 s.merge(u,tot); 71 s.merge(v,tot); 72 } 73 } 74 } 75 int main() { 76 n=getint(),m=getint(),max[n*m*2-1]=getint(); 77 for(register int i=0;i<n;i++) { 78 for(register int j=1;j<m;j++) { 79 e[cnt++]=(Edge){id(i,j-1),id(i,j),getint()}; 80 } 81 } 82 for(register int i=1;i<n;i++) { 83 for(register int j=0;j<m;j++) { 84 e[cnt++]=(Edge){id(i-1,j),id(i,j),getint()}; 85 } 86 } 87 kruskal(); 88 for(register int i=1;i<=tot;i++) { 89 f[i]=((int64)f[ch[i][0]]*f[ch[i][1]]+max[i]-min[i]+1)%mod; 90 } 91 printf("%d\n",f[tot]); 92 return 0; 93 }