1. 程式人生 > >[POI2018]Powód?

[POI2018]Powód?

高度 \n con mapi digi input getc sam 情況

題目大意:
  一個$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 }

[POI2018]Powód?