解题:POI 2018 Prawnicy

题面

网上好像都是堆的做法啊......我这个不算离散化是$O(n)$的说(虽然有一坨vector可能不开O2会爆炸)

题目即是让我们求是否存在一个最长的是不少于$k$个给出区间子集的区间,如果存在输出方案。我们发现当我们的左端点固定时,右端点越向右越可能不合法,但同时答案在不断扩大(好像不太严谨),这给了我们一个更新答案的条件;而当右端点固定左端点向右移动时,答案只会越来越合法同时越来越不优。这样我们就可以尺取做了,问题是如何统计当前区间是几个区间的子集呢?

事实上这不需要任何数据结构,我们将每个区间拆成左右端点分别用vector存起来,同时开一个数组用来标记,然后当我们的指针遇到区间时讨论:

如果左指针碰到左端点,检查一下这个区间的右端点是否在右指针右边,如果在且这个区间还没被标记,则标记它并记录贡献

如果右指针扫过右端点(注意是扫过),检查一下这个区间是否被标记,如果被标记则移除它的贡献

如果右指针碰到右端点,检查一下这个区间的左端点是否在左指针左边,如果在且这个区间还没被标记,则标记它并记录贡献

这样如果不算离散化就是$O(n)$的辣

 1 #include<cstdio>
 2 #include<vector>
 3 #include<cstring>
 4 #include<utility>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N=1000005;
 8 vector<pair<int,int> > ln[2*N],rn[2*N];
 9 int n,k,c,p1,p2,a1,a2,cnt,xnt,tot,ans;
10 int ll[N],rr[N],uni[2*N],mark[N];
11 void renew(int typ)
12 {
13     if(!typ)
14     {
15         for(int i=0;i<(int)ln[p1].size();++i)
16             if(ln[p1][i].first>=p2) 
17                 if(!mark[ln[p1][i].second])
18                     mark[ln[p1][i].second]=true,xnt++;
19     }
20     else
21     {
22         for(int i=0;i<(int)rn[p2-1].size();i++)
23             if(mark[rn[p2-1][i].second])
24                 mark[rn[p2-1][i].second]=false,xnt--;
25         for(int i=0;i<(int)rn[p2].size();i++)
26             if(rn[p2][i].first<=p1)
27                 if(!mark[rn[p2][i].second])
28                     mark[rn[p2][i].second]=true,xnt++;
29     }
30 }
31 int main ()
32 {
33     scanf("%d%d",&n,&k);
34     for(int i=1;i<=n;i++)
35     {
36         scanf("%d%d",&ll[i],&rr[i]);
37         uni[++tot]=ll[i],uni[++tot]=rr[i];
38     }
39     sort(uni+1,uni+1+tot),tot=unique(uni+1,uni+1+tot)-uni-1;
40     for(int i=1;i<=n;i++)
41     {
42         ll[i]=lower_bound(uni+1,uni+1+tot,ll[i])-uni;
43         rr[i]=lower_bound(uni+1,uni+1+tot,rr[i])-uni;
44         ln[ll[i]].push_back(make_pair(rr[i],i));
45         rn[rr[i]].push_back(make_pair(ll[i],i));
46     }
47     p1=p2=0; 
48     while(p1<=tot&&p2<=tot)
49     {
50         if(p1>p2) p2=p1,renew(1); 
51         if(xnt>=k) 
52         {
53             while(xnt>=k&&p2<=tot) p2++,renew(1); 
54             if(uni[p2-1]-uni[p1]>ans) ans=max(ans,uni[p2-1]-uni[p1]),a1=p1,a2=p2-1; 
55         }
56         p1++,renew(0);
57     }
58     printf("%d
",ans); 
59     for(int i=1;i<=n&&c<k;i++)
60         if(ll[i]<=a1&&rr[i]>=a2)
61             printf("%d ",i),c++;
62     return 0;
63 }
View Code
原文地址:https://www.cnblogs.com/ydnhaha/p/9861471.html