排序列表

15 篇文章 0 订阅
9 篇文章 0 订阅

题目大意

有若干个区间,C(m)表示所有包含m这个点的区间编号排序后的序列。
求本质不同的非空字典序第k小的序列。

做法

先离散化,因为本质不同不会超过2n个序列。
接下来顺序扫,并维护每个位置的hash值。
遇到之前出现过的hash值就叉掉。
然后接下来枚举按字典序枚举,每次看看往字典序末尾加入i会有多少种可能。
对于k,如果它不在答案序列中,不能选择它区间所包含的m。
对于k,如果它在答案序列中,只能选择它区间所包含的m。
所以需要线段树。
还要注意每次要检查当前答案序列后面能不能不放东西了,这个也可以线段树。

#include<cstdio>
#include<algorithm>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10,inf=10000000,mo1=1000000007,mo2=998244353;
typedef long long ll;
typedef pair<int,int> pi;
pi zlt;
map<pi,bool> s;
int father[maxn],tree[maxn][2],mic[maxn][2],ha[maxn][2],size[maxn];
int h[maxn*2],go[maxn*2],nxt[maxn*2],fx[maxn*2];
int sum[maxn*8],mi[maxn*8],ad[maxn*8];
bool bz[maxn*8];
int a[maxn],b[maxn],d[maxn*2],ans[maxn];
int i,j,k,l,r,t,n,m,tot,top,cnt,root;
bool czy;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}
void add(int x,int y,int z){
    go[++cnt]=y;
    fx[cnt]=z;
    nxt[cnt]=h[x];
    h[x]=cnt;
}
void build(int p,int l,int r){
    if (l==r){
        sum[p]=1;
        return;
    }
    int mid=(l+r)/2;
    build(p*2,l,mid);build(p*2+1,mid+1,r);
    sum[p]=sum[p*2]+sum[p*2+1];
}
void markcl(int p){
    bz[p]=1;
    sum[p]=0;
    mi[p]=inf;
}
void markad(int p,int v){
    ad[p]+=v;
    mi[p]+=v;
}
void down(int p){
    if (bz[p]){
        markcl(p*2);
        markcl(p*2+1);
        bz[p]=0;
    }
    if (ad[p]){
        markad(p*2,ad[p]);
        markad(p*2+1,ad[p]);
        ad[p]=0;
    }
}
void change(int p,int l,int r,int a,int b){ 
    if (a>b) return;
    if (l==a&&r==b){
        markcl(p);
        return;
    }
    down(p);
    int mid=(l+r)/2;
    if (b<=mid) change(p*2,l,mid,a,b);
    else if (a>mid) change(p*2+1,mid+1,r,a,b);
    else change(p*2,l,mid,a,mid),change(p*2+1,mid+1,r,mid+1,b);
    sum[p]=sum[p*2]+sum[p*2+1];
}
int query(int p,int l,int r,int a,int b){
    if (l==a&&r==b) return sum[p];
    down(p);
    int mid=(l+r)/2;
    if (b<=mid) return query(p*2,l,mid,a,b);
    else if (a>mid) return query(p*2+1,mid+1,r,a,b);
    else return query(p*2,l,mid,a,mid)+query(p*2+1,mid+1,r,mid+1,b);
}
void change2(int p,int l,int r,int a,int b,int v){
    if (l==a&&r==b){    
        markad(p,v);
        return;
    }
    down(p);
    int mid=(l+r)/2;
    if (b<=mid) change2(p*2,l,mid,a,b,v);
    else if (a>mid) change2(p*2+1,mid+1,r,a,b,v);
    else change2(p*2,l,mid,a,mid,v),change2(p*2+1,mid+1,r,mid+1,b,v);
    mi[p]=min(mi[p*2],mi[p*2+1]);
}
int pd(int x){
    return tree[father[x]][1]==x;
}
void update(int x){
    size[x]=size[tree[x][0]]+size[tree[x][1]]+1;
    int t=((ll)ha[tree[x][0]][0]*(n+1)%mo1+x)%mo1;
    t=((ll)t*mic[size[tree[x][1]]][0]%mo1+ha[tree[x][1]][0])%mo1;
    ha[x][0]=t;
    t=((ll)ha[tree[x][0]][1]*(n+1)%mo2+x)%mo2;
    t=((ll)t*mic[size[tree[x][1]]][1]%mo2+ha[tree[x][1]][1])%mo2;
    ha[x][1]=t;
}
void rotate(int x){
    int y=father[x],z=pd(x);
    father[x]=father[y];
    if (father[y]) tree[father[y]][pd(y)]=x;
    tree[y][z]=tree[x][1-z];
    if (tree[x][1-z]) father[tree[x][1-z]]=y;
    tree[x][1-z]=y;
    father[y]=x;
    update(y);
    update(x);
}
void splay(int x,int y){
    while (father[x]!=y){
        if (father[father[x]]!=y)
            if (pd(x)==pd(father[x])) rotate(father[x]);else rotate(x);
        rotate(x);
    }
}
void insert(int &x,int y){
    if (!x){
        x=y;
        update(x);
        return;
    }
    if (y<x){
        insert(tree[x][0],y);
        father[tree[x][0]]=x;
    }
    else{
        insert(tree[x][1],y);
        father[tree[x][1]]=x;
    }
    update(x);
}
int merge(int a,int b){
    if (!a||!b) return a+b;
    while (tree[a][1]) a=tree[a][1];
    splay(a,0);
    tree[a][1]=b;
    father[b]=a;
    update(a);
    return a;
}
int main(){
    freopen("list.in","r",stdin);freopen("list.out","w",stdout);
    n=read();m=read();
    fo(i,1,n) d[++top]=a[i]=read(),d[++top]=b[i]=read();
    sort(d+1,d+top+1);
    top=unique(d+1,d+top+1)-d-1;
    fo(i,1,n){
        a[i]=lower_bound(d+1,d+top+1,a[i])-d;
        a[i]++;
        b[i]=lower_bound(d+1,d+top+1,b[i])-d;
        change2(1,1,top,a[i],b[i],1);
    }
    //change2(1,1,top,1,1,inf);
    build(1,1,top);
    fo(i,1,n){
        add(a[i],i,1);
        add(b[i]+1,i,-1);
    }
    mic[0][0]=mic[0][1]=1;
    fo(i,1,n){
        mic[i][0]=(ll)mic[i-1][0]*(n+1)%mo1;
        mic[i][1]=(ll)mic[i-1][1]*(n+1)%mo2;
    }
    fo(i,1,top){
        t=h[i];
        while (t){
            if (fx[t]==-1){
                splay(go[t],0);
                father[tree[go[t]][0]]=father[tree[go[t]][1]]=0;
                root=merge(tree[go[t]][0],tree[go[t]][1]);
            }
            t=nxt[t];
        }
        t=h[i];
        while (t){
            if (fx[t]==1){
                insert(root,go[t]);
                splay(go[t],0);
                root=go[t];
            }
            t=nxt[t];
        }
        if (!root) change(1,1,top,i,i);
        else{
            zlt=make_pair(ha[root][0],ha[root][1]);
            if (s[zlt]){
                change(1,1,top,i,i);
            }else s[zlt]=1;
        }
    }
    fo(i,1,n){
        t=query(1,1,top,a[i],b[i]);
        if (t<m){
            m-=t;
            change(1,1,top,a[i],b[i]);
            change2(1,1,top,a[i],b[i],-1);
        }
        else{
            ans[++tot]=i;
            change(1,1,top,1,a[i]-1);
            change(1,1,top,b[i]+1,top);
            change2(1,1,top,a[i],b[i],-1);
            if (mi[1]==0) m--;
            if (m==0) break;
        }
    }
    printf("%d\n",tot);
    fo(i,1,tot) printf("%d ",ans[i]);
    printf("\n");
    fclose(stdin);fclose(stdout);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值