[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 }

 

posted @ 2018-04-03 20:50  skylee03  阅读(108)  评论(0编辑  收藏  举报