其他分享
首页 > 其他分享> > UOJ619 【JOISC2021】活动参观 2

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