题意
给出一个序列,要求资瓷以下操作:
在某个位置前插入一个数
修改某个位置的数
询问区间第k小
强制在线
原序列长度 <= 35000
插入个数 <= 35000,修改个数 <= 70000,查询个数 <= 70000 ,0 <= 每时每刻的权值 <= 70000
分析
由于强制在线且要插入,所以外层显然不能用线段树之类的静态数据结构,那么就考虑用平衡树。内层的话由于是找第k小,所以选用了线段树。
由于带旋转的平衡树每次旋转后要花费大量时间来重构线段树,所以不是很可行。我们便可以用替罪羊树。
一开始想打函数式线段树,但发现不会打垃圾回收,于是就去打了普通的线段树。区别就在于函数式线段树在暴力重构的时候是把两棵儿子的函数式线段树合并上来,然后把自己的权值加入;普通线段树就是每次把所有子节点的权值暴力加入。
不过据说时间不会相差太远。
询问的话可以把需要的节点全部拿下来然后一起跑二分。
注意要垃圾回收。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=70005;
int n,m,num,root[N],top,stack[N],rt,R;
struct tree{int l,r,s,fa,val;}t[N];
vector<int> p,q;
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;
}
struct Segtree
{
int sz;
struct tree{int l,r,s;}t[20000005];
vector<int> re;
int newnode()
{
if (!re.size()) return ++sz;
else {int x=re.back();re.pop_back();return x;}
}
void reuse(int &d)
{
if (!d) return;
reuse(t[d].l);reuse(t[d].r);
re.push_back(d);t[d].s=0;d=0;
}
void ins(int &d,int l,int r,int x,int y)
{
if (!d) d=newnode();t[d].s+=y;
if (l==r) {if (!t[d].s) reuse(d);return;}
int mid=(l+r)/2;
if (x<=mid) ins(t[d].l,l,mid,x,y);
else ins(t[d].r,mid+1,r,x,y);
if (!t[d].s) reuse(d);
}
}seg;
void dfs(int d)
{
seg.reuse(root[d]);
if (t[d].l) dfs(t[d].l);
stack[++top]=d;
if (t[d].r) dfs(t[d].r);
}
void build(int &d,int l,int r)
{
if (l>r) {d=0;return;}
int mid=(l+r)/2;d=stack[mid];
build(t[d].l,l,mid-1);if (t[d].l) t[t[d].l].fa=d;
build(t[d].r,mid+1,r);if (t[d].r) t[t[d].r].fa=d;
t[d].s=t[t[d].l].s+t[t[d].r].s+1;
for (int i=l;i<=r;i++) seg.ins(root[d],0,70000,t[stack[i]].val,1);
}
void rebuild(int d)
{
top=0;dfs(d);
int tmp=t[d].fa,op=(d==t[tmp].l?0:1);
build(d,1,top);
if (!tmp) {t[d].fa=0,rt=d;return;}
t[d].fa=tmp;
if (!op) t[tmp].l=d;
else t[tmp].r=d;
}
void ins(int &d,int x,int y)
{
if (!d) {d=++num;seg.ins(root[d],0,70000,y,1);t[d].val=y;t[d].s=1;return;}
seg.ins(root[d],0,70000,y,1);t[d].s++;
if (t[t[d].l].s+1>=x) ins(t[d].l,x,y),t[t[d].l].fa=d;
else ins(t[d].r,x-t[t[d].l].s-1,y),t[t[d].r].fa=d;
if (t[d].s*0.75<max(t[t[d].l].s,t[t[d].r].s)) R=d;
}
int modify(int d,int x,int y)
{
seg.ins(root[d],0,70000,y,1);
if (t[t[d].l].s+1==x)
{
int w=t[d].val;t[d].val=y;
seg.ins(root[d],0,70000,w,-1);
return w;
}
int w;
if (t[t[d].l].s>=x) w=modify(t[d].l,x,y);
else w=modify(t[d].r,x-t[t[d].l].s-1,y);
seg.ins(root[d],0,70000,w,-1);
return w;
}
void get(int d,int l,int r)
{
if (l>r) return;
if (l==1&&r==t[d].s) {p.push_back(root[d]);return;}
int x=t[t[d].l].s,y=t[d].s;
if (l<=x+1&&r>=x+1) q.push_back(d);
get(t[d].l,l,min(x,r));get(t[d].r,max(1,l-x-1),r-x-1);
}
int query(int x,int y,int k)
{
p.clear();q.clear();
get(rt,x,y);
int l=0,r=70000;
while (l<r)
{
int s=0,mid=(l+r)/2;
for (int i=0;i<p.size();i++) s+=seg.t[seg.t[p[i]].l].s;
for (int i=0;i<q.size();i++) s+=(t[q[i]].val<=mid&&t[q[i]].val>=l);
if (s>=k)
{
r=mid;
for (int i=0;i<p.size();i++) p[i]=seg.t[p[i]].l;
}
else
{
l=mid+1;k-=s;
for (int i=0;i<p.size();i++) p[i]=seg.t[p[i]].r;
}
}
return l;
}
int main()
{
n=read();
for (int i=1;i<=n;i++)
{
int x=read();
ins(rt,i,x);
if (R) rebuild(R),R=0;
}
m=read();int ans=0;
while (m--)
{
char ch[2];
scanf("%s",ch);int l=read()^ans,r=read()^ans;
if (ch[0]=='Q')
{
int k=read()^ans;
printf("%d\n",ans=query(l,r,k));
}
else if (ch[0]=='M') modify(rt,l,r);
else
{
ins(rt,l,r);
if (R) rebuild(R),R=0;
}
}
return 0;
}