cf1181D Irrigation[思維+權值線段樹求第k小]

傳送門

題意:給一個長爲n的數組,q次詢問(n,q<=5e5),每次給一個k(k<=1e18),求第k次填數是填第幾個數(每次填數選擇最小的數進行+1操作,如果有多個優先加下標最小的那個)

題解:離線,又由於每次改變都是成塊地改變,所以可以成塊改變就成塊改變,不能成塊改變就直接求第k小,可以用權值線段樹求第k小

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" is "<<x<<endl;

const int maxn=5e5+5;
const double eps=1e-3;
const ll inf=1e18;

struct pot{
    int id;
    ll cnt;
}p[maxn],que[maxn];

ll a[maxn],b[maxn];
int c[maxn],ans[maxn];

bool cmp1(struct pot aa,struct pot bb){
    if(aa.cnt!=bb.cnt)return aa.cnt<bb.cnt;
    return aa.id<bb.id;
}

bool cmp2(struct pot aa,struct pot bb){
    if(aa.cnt!=bb.cnt)return aa.cnt<bb.cnt;
    return aa.id<bb.id;
}

struct node{
    int l;
    int r;
    int val;
}no[maxn<<2];

void build(int rt,int l,int r){
    no[rt].l=l;
    no[rt].r=r;
    no[rt].val=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build((rt<<1),l,mid);
    build((rt<<1)|1,mid+1,r);
}

void pushup(int rt){
    no[rt].val=no[rt<<1].val+no[(rt<<1)|1].val;
}

void update(int rt,int l,int r,int pos){
    if(l==r){
        no[rt].val=1;
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=pos)update((rt<<1),l,mid,pos);
    else update((rt<<1)|1,mid+1,r,pos);
    pushup(rt);
}

int query(int rt,int l,int r,int pos){
    if(l==r)return l;
    int mid=(l+r)>>1;
    if(no[rt<<1].val>=pos)return query(rt<<1,l,mid,pos);
    else return query((rt<<1)|1,mid+1,r,pos-no[rt<<1].val);
}

int main(){
    int n,m,q;
    scanf("%d%d%d",&n,&m,&q);

    for(int i=1;i<=m;i++){
        p[i].id=i;
        p[i].cnt=0;
    }
    for(int i=1;i<=n;i++){
        int w;
        scanf("%d",&w);
        p[w].cnt++;
    }
    for(int i=1;i<=q;i++){
        scanf("%lld",&que[i].cnt);
        que[i].cnt-=n;
        que[i].id=i;
    }

    sort(p+1,p+1+m,cmp1);
    sort(que+1,que+1+q,cmp2);

    build(1,1,m);
    int st=0;
    ll sum=0;
    ll w=0;
    for(int i=1;i<=q;i++){
        ll k=que[i].cnt-w;
        while(st<m&&p[st+1].cnt*st-sum<k){
            k-=(p[st+1].cnt*st-sum);
            w+=(p[st+1].cnt*st-sum);
            sum=p[st+1].cnt*(st+1);
            st++;
            update(1,1,m,p[st].id);
        }
        k%=(st);
        if(!k)k=st;
        int w=query(1,1,m,k);
        ans[que[i].id]=w;
    }
    for(int i=1;i<=q;i++){
        printf("%d\n",ans[i]);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章