UOJ619 【JOISC2021】活动参观 2
作者:互联网
UOJ619 【JOISC2021】活动参观 2
倍增
昨天头痛,写了一堆毒瘤代码,只拿了\(1pts\)。
今天仔细看了一看,发现有点水。
我们考虑按照编号从小到大加入,相当于强行钦定一个区间必须加入,判断是否合法。
首先,我们一定是把当前区间加入一个没有被覆盖过的区间中,从而把整个区间划成\(3\)段,中间一段就是我们钦定的区间,贡献为\(1\),我们只需要计算剩下两段的贡献。
剩下两段的贡献,本质上来说,就是一个区间内最多能够包含多少个子区间。
我们可以贪心,比如从右往左加入区间,我们必然希望第一个区间的左端点尽量靠右,之后的区间同样要使左端点尽量靠右,显然这样可以得到最优解。
实际上,我们选取区间的过程是重复的,每次我们都会选取左端点尽量靠右的区间,因此我们可以倍增处理,容易得到一个区间的答案。
然后判断是否可行,可行的话就拆分区间,用\(\operatorname{set}\)维护,即可快速找到当前区间所包含的区间。
蒟蒻的代码中用了线段树判断区间是否相交,实际上这个直接在\(\operatorname{set}\)中查询即可(这是昨天毒瘤代码的遗留)。
\(Code:\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#define N 100005
#define pr pair<int,int>
#define mp make_pair
#define IT set< pr > :: iterator
using namespace std;
const int INF=1000000007;
int n,k,c0,cnt,ck[N << 1];
int a0,ans[N];
map< pr , int >H;
int st[N << 1][22];
void ckmax(int &x,int y)
{
x=(x>y)?x:y;
}
struct seg
{
int l,r;
bool operator < (const seg &A) const
{
return r<A.r;
}
}g[N],h[N];
#define s(p) tr[p].S
#define tag(p) tr[p].Tag
struct node2
{
bool S,Tag;
}tr[N << 4];
void push_tag(int p)
{
s(p)=true;
tag(p)=true;
}
void push_down(int p)
{
if (tag(p))
{
push_tag(p << 1);
push_tag(p << 1 | 1);
tag(p)=0;
}
}
void update(int p)
{
s(p)=s(p << 1)|s(p << 1 | 1);
}
void modify(int p,int l,int r,int x,int y)
{
if (x>y)
return;
if (l==x && r==y)
{
push_tag(p);
return;
}
push_down(p);
int mid(l+r >> 1);
if (y<=mid)
modify(p << 1,l,mid,x,y); else
if (x>mid)
modify(p << 1 | 1,mid+1,r,x,y); else
{
modify(p << 1,l,mid,x,mid);
modify(p << 1 | 1,mid+1,r,mid+1,y);
}
update(p);
}
bool calc(int p,int l,int r,int x,int y)
{
if (l==x && r==y)
return s(p);
push_down(p);
int mid(l+r >> 1);
if (y<=mid)
return calc(p << 1,l,mid,x,y); else
if (x>mid)
return calc(p << 1 | 1,mid+1,r,x,y); else
return calc(p << 1,l,mid,x,mid)||calc(p << 1 | 1,mid+1,r,mid+1,y);
}
int calc(int l,int r)
{
if (l>r)
return 0;
if (H.find(mp(l,r))!=H.end())
return H[mp(l,r)];
int e(0),x(r);
for (int i=20;i>=0;--i)
if (st[x][i]>=l)
e+=(1 << i),x=st[x][i];
return H[mp(l,r)]=e;
}
set< pr >ps;
int main()
{
scanf("%d%d",&n,&k);
for (int i=1;i<=n;++i)
scanf("%d%d",&g[i].l,&g[i].r),ck[++c0]=g[i].l,ck[++c0]=g[i].r;
sort(ck+1,ck+c0+1);
c0=unique(ck+1,ck+c0+1)-ck-1;
for (int i=1;i<=n;++i)
{
g[i].l=lower_bound(ck+1,ck+c0+1,g[i].l)-ck;
g[i].r=lower_bound(ck+1,ck+c0+1,g[i].r)-ck;
h[i]=g[i];
}
sort(h+1,h+n+1);
int o(1);
for (int i=1;i<=c0;++i)
{
memcpy(st[i],st[i-1],sizeof(st[i-1]));
while (o<=n && h[o].r==i)
{
int l(h[o].l);
ckmax(st[i][0],l);
++o;
}
for (int j=1;st[i][j-1] && j<=20;++j)
st[i][j]=st[st[i][j-1]][j-1];
}
cnt=calc(1,c0);
if (cnt<k)
{
puts("-1");
return 0;
}
for (int i=1;i<=n;++i)
{
int l(g[i].l),r(g[i].r);
if (calc(1,1,c0*2,l*2+1,r*2-1))
continue;
IT it=ps.upper_bound(mp(r-1,INF));
int cl,cr;
if (it==ps.end())
cr=c0; else
cr=it->first;
if (it==ps.begin())
cl=1; else
--it,cl=g[it->second].r;
int t0(calc(cl,cr)),t1(calc(cl,l)),t2(calc(r,cr));
if (cnt-t0+t1+t2+1>=k)
{
ans[++a0]=i;
cnt=cnt-t0+t1+t2+1;
ps.insert(mp(l,i));
modify(1,1,c0*2,l*2+1,r*2-1);
if (a0==k)
break;
}
}
for (int i=1;i<=a0;++i)
printf("%d\n",ans[i]);
return 0;
}
标签:cnt,return,参观,int,JOISC2021,UOJ619,区间,include,define 来源: https://www.cnblogs.com/GK0328/p/14724151.html