[ZJOI2013] K 大数查询
沃市区。
题目思路
整体二分加线段树。二分答案(第 \(c\) 大的数具体是多少,范围是 \([L,R]\))后,我们就处理当前含有的询问。
设 \(mid=L+R>>1\)(注意到这种写法在此题十分重要,因为 \((L+R)/2\) 这个写法向 \(0\) 取整)。
插入 \(x\) 的操作如果满足 \(x \le mid\),则该插入操作会影响下一层左侧(答案范围是 \([L,mid]\) )的答案。故应该加入线段树。
询问操作就板板的。
注意到这道题目是求第 \(k\) 大的数字,可以取反后套熟悉的板子。最后输出时记得恢复。
🍭🍭错误:
真是连续做两道都忘了 else 以及其中的加入操作。
else{
int tot=query(1,1,n,q[i].l,q[i].r);
if(tot>=q[i].c) q1[++p1]=q[i];
else q[i].c-=tot,q2[++p2]=q[i];
}
AC Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e4+5;
int n,m,qcnt,cnt,t[N<<2],tag[N<<2],ans[N];
struct node{
int bz,l,r,c,id;
}q[N],q1[N],q2[N];
int lc(int p){return p<<1;}
int rc(int p){return p<<1|1;}
void pushup(int p){
t[p]=t[lc(p)]+t[rc(p)];
}
void pushdown(int p,int l,int r){
if(tag[p]){
int mid=l+r>>1;
tag[lc(p)]+=tag[p];
tag[rc(p)]+=tag[p];
t[lc(p)]+=(mid-l+1)*tag[p];
t[rc(p)]+=(r-mid)*tag[p];
tag[p]=0;
}
}
void update(int p,int l,int r,int L,int R,int d){
if(L<=l&&r<=R){
tag[p]+=d;
t[p]+=d*(r-l+1);
return ;
}
pushdown(p,l,r);
int mid=l+r>>1;
if(L<=mid) update(lc(p),l,mid,L,R,d);
if(mid<R) update(rc(p),mid+1,r,L,R,d);
pushup(p);
}
int query(int p,int l,int r,int L,int R){
if(L<=l&&r<=R) return t[p];
pushdown(p,l,r);
int mid=l+r>>1,ans=0;
if(L<=mid) ans+=query(lc(p),l,mid,L,R);
if(mid<R) ans+=query(rc(p),mid+1,r,L,R);
return ans;
}
void solve(int l,int r,int L,int R){
if(L==R){
for(int i=l;i<=r;i++) ans[q[i].id]=L;
return ;
}
int mid=L+R>>1,p1=0,p2=0;
for(int i=l;i<=r;i++){
if(q[i].bz==1){
if(q[i].c<=mid){
update(1,1,n,q[i].l,q[i].r,1);
q1[++p1]=q[i];
}
else q2[++p2]=q[i];
}
else{
int tot=query(1,1,n,q[i].l,q[i].r);
if(tot>=q[i].c) q1[++p1]=q[i];
else q[i].c-=tot,q2[++p2]=q[i];
}
}
for(int i=l;i<=r;i++){
if(q[i].bz==1&&q[i].c<=mid) update(1,1,n,q[i].l,q[i].r,-1);
}
for(int i=1;i<=p1;i++) q[l+i-1]=q1[i];
for(int i=1;i<=p2;i++) q[l+p1+i-1]=q2[i];
solve(l,l+p1-1,L,mid);solve(l+p1,r,mid+1,R);
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m;
for(int i=1,op,l,r,c;i<=m;i++){
cin>>op>>l>>r>>c;
if(op==1) q[i]={op,l,r,-c,0};//取反,求第 c 小
else q[i]={op,l,r,c,++qcnt};
}
solve(1,m,-n,n);
for(int i=1;i<=qcnt;i++) cout<<-ans[i]<<"\n";
return 0;
}
古顾故

浙公网安备 33010602011771号