洛谷P1533 可怜的狗狗
平衡树 莫队
一看到平衡树的标签就上去杠了。。。结果发现是主席树裸题。。。然而我不会
求区间第k大。因为是离线,所以可以乱搞。这里我用的是平衡树+莫队。
对询问进行排序,然后用莫队的思想进行插入/删除节点,最后查询答案。这些操作可以用平衡树。
然后就艹过去了。。。
代码:
#include<cmath>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define N 300000
#define M 50000
#define inf -0x7fffffff
using namespace std;
struct node{
int w,rnd,to[2],p,size;
}t[N*10+5];//这里极端情况应该要2700w的
struct qstn{
int l,r,k,bl,br,id;
}que[M+5];
int n,m,rt,S,nd;
int ans[M+5],a[N+5];
inline char readc(){//fread读优
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; return *l++;
}
inline int _read(){
int num=0,f=1; char ch=readc();
while (!isdigit(ch)) {if (ch=='-') f=-f;ch=readc();}
while (isdigit(ch)) num=num*10+ch-48,ch=readc();
return num*f;
}
int f(int x){ return x/S; }//分块
bool cmp(qstn x,qstn y){ return (f(x.l)<f(y.l))||(f(x.l)==f(y.l)&&x.r<y.r); }
void rtt(int &x,int fl){
int s=t[x].to[fl];
t[x].to[fl]=t[s].to[fl^1];
t[s].to[fl^1]=x;
t[s].size=t[x].size;
t[x].size=t[t[x].to[0]].size+t[t[x].to[1]].size+t[x].p;
x=s;
}
void nsrt(int &x,int w){
if (!x){
t[x=++nd].w=w; t[x].p=t[x].size=1;
t[x].rnd=rand(); return;
}
t[x].size++;
if (t[x].w==w) t[x].p++;
else{
int flag=t[x].w<w;
nsrt(t[x].to[flag],w);
if (t[x].rnd>t[t[x].to[flag]].rnd) rtt(x,flag);
}
}
void dlt(int &x,int w){
if (!x) return;
if (t[x].w==w){
if (t[x].p>1) { t[x].p--; t[x].size--; return; }
if (!t[x].to[0]) { x=t[x].to[1]; return; }
if (!t[x].to[1]) { x=t[x].to[0]; return; }
int flag=t[t[x].to[0]].rnd<t[t[x].to[1]].rnd;
rtt(x,flag^1),dlt(x,w);
}
else{
t[x].size--;
int flag=t[x].w<w;
dlt(t[x].to[flag],w);
}
}
int srch(int x,int w){
if (!x) return 0;
if (t[t[x].to[0]].size>=w)
return srch(t[x].to[0],w);
if (t[t[x].to[0]].size+t[x].p>=w)
return t[x].w;
return srch(t[x].to[1],w-t[t[x].to[0]].size-t[x].p);
}
void Insert(int l,int r){ for (int i=l;i<=r;i++) nsrt(rt,a[i]); }//插入(平衡树维护)
void Delete(int l,int r){ for (int i=l;i<=r;i++) dlt(rt,a[i]); }//删除(平衡树维护)
int main(){
n=_read(),m=_read(),S=sqrt(n);
for (int i=1;i<=n;i++) a[i]=_read();
for (int i=1;i<=m;i++){
que[i].l=_read(),que[i].r=_read();
que[i].k=_read(),que[i].id=i;
}
sort(que+1,que+m+1,cmp);//排序
Insert(que[1].l,que[1].r); //先把第一个询问加进去
ans[que[1].id]=srch(rt,que[1].k);
int l=que[1].l,r=que[1].r;
for (int i=2;i<=m;i++){//莫队乱搞
if (que[i].l>l) Delete(l,que[i].l-1);
else Insert(que[i].l,l-1);
if (que[i].r>r) Insert(r+1,que[i].r);
else Delete(que[i].r+1,r);
ans[que[i].id]=srch(rt,que[i].k);
l=que[i].l,r=que[i].r;
}
for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}