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; } }
莫队回滚:不会
标签:第二场,cnt,int,tr,cin,初赛,st,2022,ans From: https://www.cnblogs.com/er007/p/16633379.html