[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 #include<sys/stat.h>
 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+1;
33 int ans[N];
34 struct Segment {
35     int l,r,id;
36     bool operator < (const Segment &another) const {
37         return l<another.l;
38     }
39 };
40 Segment seg[N];
41 std::priority_queue<int,std::vector<int>,std::greater<int> > q1;
42 std::priority_queue<std::pair<int,int>,std::vector<std::pair<int,int> >,std::greater<std::pair<int,int> > > q2;
43 int main() {
44     const int n=getint(),k=getint();
45     for(register int i=1;i<=n;i++) {
46         const int l=getint(),r=getint();
47         seg[i]=(Segment){l,r,i};
48     }
49     std::sort(&seg[1],&seg[n]+1);
50     int pos;
51     for(register int i=1;i<=n;i++) {
52         while((int)q1.size()>=k) q1.pop();
53         q1.push(seg[i].r);
54         if(i>=k&&q1.top()-seg[i].l>ans[0]) {
55             ans[0]=q1.top()-seg[pos=i].l;
56         }
57     }
58     for(register int i=1;i<=pos;i++) {
59         while((int)q2.size()>=k) q2.pop();
60         q2.push(std::make_pair(seg[i].r,seg[i].id));
61     }
62     for(register int i=1;i<=k;i++) {
63         ans[i]=q2.top().second;
64         q2.pop();
65     }
66     printf("%d\n",ans[0]);
67     for(register int i=1;i<=k;i++) {
68         printf("%d%c",ans[i]," \n"[i==k]);
69     }
70     return 0;
71 }

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

时间: 2024-08-01 17:26:36

[POI2018]Prawnicy的相关文章

【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

【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=

[POI2018]Pow&#243;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]]\tim

[POI 2018] Prawnicy

[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=5102 [算法] 首先,n条线段的交集一定是[Lmax,Rmin] , 其中,Lmax为最靠右的左端点,Rmin为最靠左的右端点 根据这个性质 , 我们不妨将所有线段按左端点为关键字排序 , 依次枚举最终交集的左端点 , 同时 , 我们还需维护一个小根堆 , 维护前k大的右端点 , 每次我们通过( 堆顶 - 当前枚举线段的左端点 )更新答案 [代码] #include<bits/st

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

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