2022 百度之星初赛 第二场 A

A题:

题目:

 

 

双指针,莫队回滚,线段树,归并树都可以过

线段树:

做法1.给每个节点存当前区间前 k 大的数

做法2.存最大值和它的位置

#define int ll
const int N = 1e5+10;
int n,q,k,x;

int a[N];
struct node {
    int l,r,mk;//
    V<int> v;
} tr[4 * N];
bool cmp(int a,int b) {
    return a > b;
}
void push_up(int p) {
    V<int> pp;
    for(auto it:tr[p<<1].v) {
        pp.push_back(it);
    }
    for(auto it:tr[p<<1|1].v) {
        pp.push_back(it);
    }
    int cnt = 0;;
    sort(pp.begin(),pp.end(),cmp);
    for(auto it:pp) {
        tr[p].v.push_back(it);
        cnt ++ ;
        if(cnt >= k) break;
    }
}

void build(int p,int l,int r) {
    tr[p] = {l,r};
    if(l == r) {
        tr[p].mk = a[l];
        tr[p].v.push_back(a[l]);
        rt;
    }
    int mid = l + r >> 1;
    build(p<<1,l,mid);build(p<<1|1,mid+1,r);
    push_up(p);
}

V<int> query1(int p,int l,int r) {
    if(l <= tr[p].l && tr[p].r <= r) {
//        db(tr[p].v[0]);
//        dbb(l,r);
//        dbb(tr[p].l,tr[p].r);
        return tr[p].v;
    }
    int mid = tr[p].l + tr[p].r >> 1,ans = 0;
    V<int> que;
    if(l <= mid) {
        que = query1(p<<1,l,r);
    }
    
    if(mid < r) {
        
        V<int> tmp = query1(p<<1|1,l,r);
        for(auto it:tmp) {
            que.push_back(it);
        } 
    }
    V<int> tmp;
    sort(all(que),cmp); 
    int leng = que.size();
    for(int i = 0;i<min(k,leng) ;i++) {
        tmp.push_back(que[i]);
    }
//    dbb(l,r);
//    db(tmp.size());
    return tmp;
}

void solve()
{
    cin>>n>>q>>k>>x;
    fo(i,1,n) cin>>a[i];
    build(1,1,n);
    while(q -- ) {
        int l,r;cin>>l>>r;
        if(r < l) {
            cout<<"N"<<endl;
            continue;
        }
        V<int> tmp = query1(1,l,r);
        int cnt = 0;
        ll res = 0;
//        db(tmp.size());
        for(auto it:tmp) {
            res += it;
            cnt ++;
            if(cnt == k) break;
        }
//        cout<<res<<endl;
        if(res >= x) {
            cout<<"Y"<<endl;
        } else {
            cout<<"N"<<endl;
        }
    }
    rt;
}

双指针:

求对于每个r 最早的 l 在哪里。

如果[l,r]满足条件 [l,r+1] 也满足条件

所以可以用双指针判断对于每个 r 最早的 l 在哪里

可以用set<int,greater<int>> st存 每个数,挨个判断最前面的数在里面是否满足条件

如果满足条件就删掉,直到遇到不满足条件的时候,再重新装进去

这个时候枚举到的 j 就是对于这个 r 最早的 l

const int N = 1e5+10;
int n,q,k,x;

int a[N],ans[N];

void solve()
{
//    cin>>n>>m;
    ms(ans,-0x3f)
    set<int,greater<int>> st;
    cin>>n>>q>>k>>x;
    fo(i,1,n) cin>>a[i];
    int j = 1;
    fo(i,1,n) {
         auto check = [&]()->int{
             int sum = 0,cnt = 0;
             for(auto y:st) {
                 cnt ++ ;
                 sum += y;
                 if(sum >= x) return 1;
                 if(cnt == k) break;
             }
             return 0;
         };
         
         st.insert(a[i]);
         if(!check()) continue;
         while(check()) st.erase(st.find(a[j])),j++;
         j -- ;
         st.insert(a[j]);
         ans[i] = j;
    }
    while(q -- ) {
        int l,r;cin>>l>>r;
        if(ans[r] >= l) {
            cout<<"Y"<<endl;
        } else cout<<"N"<<endl;
    }
}

莫队回滚:不会

 

posted @ 2022-08-28 18:47  er007  阅读(188)  评论(0编辑  收藏  举报