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

原文地址:https://www.cnblogs.com/skylee03/p/8711067.html

时间: 2024-10-10 12:26:58

[POI2018]Powód?的相关文章

【BZOJ5101】[POI2018]Pow&#243;d 并查集

[BZOJ5101][POI2018]Powód Description 在地面上有一个水箱,它的俯视图被划分成了n行m列个方格,相邻两个方格之间有一堵厚度可以忽略不计的墙,水箱与外界之间有一堵高度无穷大的墙,因此水不可能漏到外面.已知水箱内每个格子的高度都是[0,H]之间的整数,请统计有多少可能的水位情况.因为答案可能很大,请对10^9+7取模输出.两个情况不同当且仅当存在至少一个方格的水位在两个情况中不同. Input 第一行包含三个正整数n,m,H(n*m<=500000,1<=H<

【BZOJ5099】[POI2018]Pionek 几何+双指针

[BZOJ5099][POI2018]Pionek Description 在无限大的二维平面的原点(0,0)放置着一个棋子.你有n条可用的移动指令,每条指令可以用一个二维整数向量表示.每条指令最多只能执行一次,但你可以随意更改它们的执行顺序.棋子可以重复经过同一个点,两条指令的方向向量也可能相同.你的目标是让棋子最终离原点的欧几里得距离最远,请问这个最远距离是多少? Input 第一行包含一个正整数n(n<=200000),表示指令条数. 接下来n行,每行两个整数x,y(|x|,|y|<=1

【BZOJ5100】[POI2018]Plan metra 构造

[BZOJ5100][POI2018]Plan metra Description 有一棵n个点的无根树,每条边有一个正整数权值,表示长度,定义两点距离为在树上的最短路径的长度. 已知2到n-1每个点在树上与1和n的距离,请根据这些信息还原出这棵树. Input 第一行包含一个正整数n(2<=n<=500000),表示点数. 第二行包含n-2个正整数d(1,2),d(1,3),...,d(1,n-1),分别表示每个点到1的距离. 第三行包含n-2个正整数d(n,2),d(n,3),...,d(

[POI2018]Pionek

[POI2018]Pionek 题目大意: 在无限大的二维平面的原点放置着一个棋子.你有\(n(n\le2\times10^5)\)条可用的移动指令,每条指令可以用一个二维整数向量表示.请你选取若干条指令,使得经过这些操作后,棋子离原点的距离最大. 思路: 将所有向量极角排序,然后你选取的向量一定是里面连续的一段,由于所有向量排成一个环,所以要复制一遍接在后面,最后用尺取法枚举左右端点即可. 时间复杂度\(\mathcal O(n\log n)\). 源代码: #include<cmath>

BZOJ5103 : [POI2018]R&#243;znorodno

从上到下枚举上下底边,那么涉及两行的添加和删除. 首先预处理出对于每一列,每个位置添加和删除时,是否会对往下$k$个里出现这个颜色造成影响. 然后对于每种颜色维护一个长度为$m$的bitset,表示哪些列出现过该颜色. 那么每次修改时,找到前驱和后继,对这一行答案的影响是一段区间加,差分前缀和即可. 时间复杂度$O(\frac{nm^2}{64})$. #include<cstdio> typedef unsigned int U; const int N=3010,M=100010,BUF=

【bzoj5102】[POI2018]Prawnicy 堆

题目描述 定义一个区间(l,r)的长度为r-l,空区间的长度为0. 给定数轴上n个区间,请选择其中恰好k个区间,使得交集的长度最大. 输入 第一行包含两个正整数n,k(1<=k<=n<=1000000),表示区间的数量. 接下来n行,每行两个正整数l,r(1<=l<r<=10^9),依次表示每个区间. 输出 第一行输出一个整数,即最大长度. 第二行输出k个正整数,依次表示选择的是输入文件中的第几个区间. 若有多组最优解,输出任意一组. 样例输入 6 3 3 8 4 12

[POI2018]Prawnicy

题目大意: 有$n(n\le10^6)$个线段,每个线段覆盖的范围是$[l_i,r_i]$,要求从中选取$k(k\le10^6)$个线段使得这些线段覆盖范围的交集最大,求最大交集及任意一种方案. 思路: 对左端点排序,用堆维护右端点即可. 1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<algorithm> 5 #include<sys/mman.h> 6 #i

bzoj 5103 [POI2018]R&#243;?norodno??

这个题没有想出来.. 首先显然的一点是我们要对每种颜色做一次不重复的贡献计算. 同种颜色的贡献就是矩形的并.从网上查了资料,矩形面积并用的是扫描线,那么这个我们也可以用扫描线了. 我们考虑枚举横坐标,维护存在于当前横坐标的所有纵坐标的区间.一个性质是所有的矩形都是边长为k的正方形,那么在加入或删除一个区间时只可能影响到一个连续的区间.我们只需要对这个区间操作就行了. 我用的set维护,因为bzoj开O2,所以比其他数据结构要快一些,但是没有bitset快,要跑47s,记得加上fread,这个题的

[武汉加油] bzoj 5099: [POI2018]Pionek 几何+双指针

几何+双指针 题目大意:现在有 \(n\) 个向量,请你选出来一些向量使它们的和的长度最大,输出最大值的平方. 假如我们已经知道了最终向量的方向,我们要想使长度最大,就需要将所有投影在最终向量正方向上的向量都加起来. 所以我们可以按角度枚举最终向量的方向,我们需要加起来的就是一段移动的区间,我们可以用双指针来维护加起来的向量. 因为最终向量的方向有可能是给出的向量,也有可能是向量之间间隔的方向,所以每次移动指针的时候都要更新一下答案. 因为开始给出的向量不一定有序,所以我们需要先将向量排序. #