[LibreOJ β Round]ZQC的手办

题目大意

区间对一个数取max。
区间求最小的x个比k小的数。

线段树

第一个操作很好搞。
第二个操作有个很显然的常数大做法。
实际上可以用堆把这个区间的笛卡尔树按优先级广搜。

#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=500000+10,inf=1000000000;
struct dong{
    int x,y;
    friend bool operator <(dong a,dong b){
        return a.xx||a.x==b.x&&a.yy;
    }
    friend dong operator +(dong a,dong b){
        if (areturn a;else return b;
    }
} tmp;
struct suan{
    int l,r,p,v;
    friend bool operator <(suan a,suan b){
        return a.v>b.v||a.v==b.v&&a.p dl;
dong tree[maxn*4];
int mx[maxn*4],a[maxn],ans[maxn],sta[80];
bool bz[maxn*4];
int i,j,k,l,r,p,t,n,m,tot,top;
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*f;
}
void build(int p,int l,int r){
    if (l==r){
        tree[p].x=a[l];
        tree[p].y=l;
        return;
    }
    int mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    tree[p]=tree[p*2]+tree[p*2+1];
}
void mark(int p,int v){
    bz[p]=1;
    mx[p]=max(mx[p],v);
    if (tree[p].xx=v;
}
void down(int p){
    if (bz[p]){
        mark(p*2,mx[p]);
        mark(p*2+1,mx[p]);
        bz[p]=0;
    }
}
void change(int p,int l,int r,int a,int b,int v){
    if (l==a&&r==b){
        mark(p,v);
        return;
    }
    down(p);
    int mid=(l+r)/2;
    if (b<=mid) change(p*2,l,mid,a,b,v);
    else if (a>mid) change(p*2+1,mid+1,r,a,b,v);
    else change(p*2,l,mid,a,mid,v),change(p*2+1,mid+1,r,mid+1,b,v);
    tree[p]=tree[p*2]+tree[p*2+1];
}
void query(int p,int l,int r,int a,int b){
    if (l==a&&r==b){
        tmp=tmp+tree[p];
        return;
    }
    down(p);
    int mid=(l+r)/2;
    if (b<=mid) query(p*2,l,mid,a,b);
    else if (a>mid) query(p*2+1,mid+1,r,a,b);
    else query(p*2,l,mid,a,mid),query(p*2+1,mid+1,r,mid+1,b);
}
int main(){
    n=read();
    fo(i,1,n) a[i]=read();
    build(1,1,n);
    m=read();
    fo(i,1,m){
        t=read();
        if (t==1){
            l=read();r=read();k=read();
            change(1,1,n,l,r,k);
        }
        else{
            l=read();r=read();k=read();j=read();
            if (r-l+1printf("-1\n");
                continue;
            }
            while (!dl.empty()) dl.pop();
            zlt.l=l;zlt.r=r;
            tmp.x=inf;
            query(1,1,n,l,r);
            zlt.p=tmp.y;zlt.v=tmp.x;
            dl.push(zlt);
            tot=0;
            while (j--){
                zlt=dl.top();
                dl.pop();
                if (zlt.v>=k) break;
                ans[++tot]=zlt.v;
                l=zlt.l;r=zlt.r;p=zlt.p;
                if (l1;
                    tmp.x=inf;
                    query(1,1,n,l,p-1);
                    zlt.p=tmp.y;zlt.v=tmp.x;
                    dl.push(zlt);
                }
                if (p1;
                    zlt.r=r;
                    tmp.x=inf;
                    query(1,1,n,p+1,r);
                    zlt.p=tmp.y;zlt.v=tmp.x;
                    dl.push(zlt);
                }
            }
            if (j>=0) printf("-1\n");
            else{
                fo(j,1,tot) printf("%d ",ans[j]);
                printf("\n");
            }
        }
    }
}

你可能感兴趣的:(堆,线段树)