Description
给定一个含有个数的序列,程序必须回答这样的询问:对于给定的,在中第小的数是多少,并且,你可以改变一些的值,改变后,程序还能针对改
变后的继续回答上面的问题。
Input
第一行有两个正整数,。
分别表示序列的长度和指令的个数。
第二行有个数,表示,这些数都小于。
接下来的行描述每条指令。
每行的格式是下面两种格式中的一种。
或者
(是数字,)表示询问指令,询问中第小的数。
表示把改变成为
Output
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
Sample Input
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
HINT
Source
思路
位置线段树套权值splay;
这里两个操作Q和C,C的话把位置线段树上每一个包含的区间全部增加一个节点减去一个节点,然后把改成;
Q操作是重点:二分答案,在位置线段树上的区间找比二分出来的小的个数,如果小于,则缩小,否则增加。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
整体二分写法:
二分答案区间,将询问与修改一起二分(分流)。
代码(树套树版)
#include <cstdio>
#include <iostream>
const int maxn=10000;
const int maxs=4000000;
int a[maxn+10];
struct splay_tree//权值splay
{
int fa[maxs+10],son[2][maxs+10],size[maxs+10],val[maxs+10],tot;
inline int t(int x)
{
return son[1][fa[x]]==x;
}
inline int updata(int x)
{
return size[x]=size[son[0][x]]+size[son[1][x]]+1;
}
inline int rotate(int x)
{
int k=t(x),f=fa[x];
if(fa[f])
{
son[t(f)][fa[f]]=x;
}
fa[x]=fa[f];
if(son[!k][x])
{
fa[son[!k][x]]=f;
}
son[k][f]=son[!k][x];
fa[f]=x;
son[!k][x]=f;
updata(f);
updata(x);
return 0;
}
inline int splay(int &root,int x,int c)
{
while(fa[x]!=c)
{
int f=fa[x];
if(fa[f]==c)
{
rotate(x);
}
else if(t(x)==t(f))
{
rotate(f);
rotate(x);
}
else
{
rotate(x);
rotate(x);
}
}
if(!c)
{
root=x;
}
return 0;
}
inline int getkth(int root,int x)
{
int now=root;
while(now)
{
if(size[son[0][now]]+1==x)
{
return now;
}
else if(size[son[0][now]]+1<x)
{
x-=size[son[0][now]]+1;
now=son[1][now];
}
else
{
now=son[0][now];
}
}
return 0;
}
inline int newnode(int x)
{
++tot;
val[tot]=x;
size[tot]=1;
son[0][tot]=son[1][tot]=0;
return tot;
}
inline int ins(int &root,int x)
{
if(!root)
{
root=newnode(x);
fa[tot]=0;
return 0;
}
int now=root;
while(now)
{
int k=val[now]<x;
if(!son[k][now])
{
son[k][now]=newnode(x);
fa[tot]=now;
break;
}
now=son[k][now];
}
splay(root,tot,0);
return 0;
}
inline int del(int &root,int x)
{
int now=root;
while(now)
{
if(val[now]==x)
{
break;
}
else
{
now=son[val[now]<x][now];
}
}
splay(root,now,0);
if((!son[0][now])&&(!son[1][now]))
{
root=0;
}
else if(!son[0][now])
{
root=son[1][now];
fa[son[1][now]]=0;
}
else if(!son[1][now])
{
root=son[0][now];
fa[son[0][now]]=0;
}
else
{
now=son[0][root];
while(son[1][now])
{
now=son[1][now];
}
splay(root,now,root);
son[1][now]=son[1][root];
fa[son[1][root]]=now;
fa[now]=0;
updata(now);
root=now;
}
return 0;
}
int getnext(int now,int x)//找严格大于x的后继
{
if(!now)
{
return 0;
}
else if(val[now]<=x)
{
return getnext(son[1][now],x);
}
else
{
int p=getnext(son[0][now],x);
if(!p)
{
return now;
}
else
{
return p;
}
}
return 0;
}
inline int getrank(int &root,int x)
{
int now=getnext(root,x);
if(!now)
{
return size[root];
}
splay(root,now,0);
return size[son[0][now]];
}
};
struct segment_tree//位置线段树
{
int root[maxn<<2];
splay_tree st;
int build(int now,int left,int right)
{
for(register int i=left; i<=right; ++i)
{
st.ins(root[now],a[i]);
}
if(left==right)
{
return 0;
}
int mid=(left+right)>>1;
build(now<<1,left,mid);
build(now<<1|1,mid+1,right);
return 0;
}
int modify(int now,int left,int right,int pos,int v)
{
st.ins(root[now],v);
st.del(root[now],a[pos]);
if(left==right)
{
return 0;
}
int mid=(left+right)>>1;
if(pos<=mid)
{
modify(now<<1,left,mid,pos,v);
}
else
{
modify(now<<1|1,mid+1,right,pos,v);
}
return 0;
}
int query(int now,int left,int right,int askl,int askr,int v)
{
if((askl<=left)&&(right<=askr))
{
int w=st.getrank(root[now],v);
return w;
}
int mid=(left+right)>>1,res=0;
if(askl<=mid)
{
res+=query(now<<1,left,mid,askl,askr,v);
}
if(mid<askr)
{
res+=query(now<<1|1,mid+1,right,askl,askr,v);
}
return res;
}
};
segment_tree st;
int n,m,aa,b,c;
char s[10];
int main()
{
scanf("%d%d",&n,&m);
for(register int i=1; i<=n; ++i)
{
scanf("%d",&a[i]);
}
st.build(1,1,n);
while(m--)
{
scanf("%s%d%d",s,&aa,&b);
if(s[0]=='C')
{
st.modify(1,1,n,aa,b);
a[aa]=b;
}
else
{
scanf("%d",&c);
int left=0,right=1000000000;
while(left<=right)
{
int mid=(left+right)>>1;
if(st.query(1,1,n,aa,b,mid)<c)
{
left=mid+1;
}
else
{
right=mid-1;
}
}
printf("%d\n",right+1);
}
}
return 0;
}
代码(整体二分版)
#include <cstdio>
#include <algorithm>
const int maxn=10000;
const int maxm=50000;
const int maxs=1000000000;
int n;
struct tree_array
{
int c[maxn+10];
inline int lowbit(int x)
{
return x&(-x);
}
inline int add(int pos,int x)
{
while(pos<=n)
{
c[pos]+=x;
pos+=lowbit(pos);
}
return 0;
}
inline int sum(int pos)
{
int res=0;
while(pos)
{
res+=c[pos];
pos-=lowbit(pos);
}
return res;
}
};
struct data
{
int l,r,k,id,type;
inline int make_data(int l_,int r_,int k_,int id_,int type_)
{
l=l_;
r=r_;
k=k_;
id=id_;
type=type_;
return 0;
}
};
data d[maxm+10],da[maxm+10],db[maxm+10];
int ans[maxm+10],tot,cnt;
tree_array t;
int solve(int l,int r,int askl,int askr)//整体二分
{
if(askl>askr)
{
return 0;
}
if(l==r)
{
for(register int i=askl; i<=askr; ++i)
{
ans[d[i].id]=l;
}
return 0;
}
int mid=(l+r)>>1,tl=0,tr=0;
for(register int i=askl; i<=askr; ++i)
{
if(d[i].type==1)
{
int tmp=t.sum(d[i].r)-t.sum(d[i].l-1);
if(tmp>=d[i].k)
{
++tl;
da[tl]=d[i];
}
else
{
d[i].k-=tmp;
++tr;
db[tr]=d[i];
}
}
else if(d[i].type==2)
{
if(d[i].k<=mid)
{
t.add(d[i].l,1);
++tl;
da[tl]=d[i];
}
else
{
++tr;
db[tr]=d[i];
}
}
else
{
if(d[i].k<=mid)
{
t.add(d[i].l,-1);
++tl;
da[tl]=d[i];
}
else
{
++tr;
db[tr]=d[i];
}
}
}
for(register int i=askl; i<=askr; ++i)
{
if(d[i].type==2)
{
if(d[i].k<=mid)
{
t.add(d[i].l,-1);
}
}
else if(d[i].type==3)
{
if(d[i].k<=mid)
{
t.add(d[i].l,1);
}
}
}
for(register int i=1; i<=tl; ++i)
{
d[askl+i-1]=da[i];
}
for(register int i=1; i<=tr; ++i)
{
d[askl+tl+i-1]=db[i];
}
solve(l,mid,askl,askl+tl-1);
solve(mid+1,r,askl+tl,askr);
return 0;
}
int num[maxn+10],m,a,b,c;
char opt[10];
int main()
{
scanf("%d%d",&n,&m);
for(register int i=1; i<=n; ++i)
{
scanf("%d",&num[i]);
++tot;
d[tot].make_data(i,i,num[i],0,2);
}
while(m--)
{
scanf("%s%d%d",opt,&a,&b);
if(opt[0]=='Q')
{
scanf("%d",&c);
++tot;
++cnt;
d[tot].make_data(a,b,c,cnt,1);
}
else
{
++tot;
d[tot].make_data(a,a,num[a],0,3);
++tot;
d[tot].make_data(a,a,b,0,2);
num[a]=b;
}
}
solve(0,maxs,1,tot);
for(register int i=1; i<=cnt; ++i)
{
printf("%d\n",ans[i]);
}
return 0;
}