Description
给定一个含有
n
n
个数的序列,程序必须回答这样的询问:对于给定的
i,j,k
i
,
j
,
k
,在
ai,ai+1,ai+2…aj
a
i
,
a
i
+
1
,
a
i
+
2
…
a
j
中第
k
k
小的数是多少,并且,你可以改变一些
ai
a
i
的值,改变后,程序还能针对改
变后的
a
a
继续回答上面的问题。
Input
第一行有两个正整数,
m(1≤m≤10000)
m
(
1
≤
m
≤
10000
)
。
分别表示序列的长度和指令的个数。
第二行有
n
n
个数,表示,这些数都小于
109
10
9
。
接下来的
m
m
行描述每条指令。
每行的格式是下面两种格式中的一种。
或者
C i t
C
i
t
Q i j k
Q
i
j
k
(
i,j,k
i
,
j
,
k
是数字,
1≤i≤j≤n,1≤k≤j−i+1
1
≤
i
≤
j
≤
n
,
1
≤
k
≤
j
−
i
+
1
)表示询问指令,询问
ai,ai+1…aj
a
i
,
a
i
+
1
…
a
j
中第
k
k
小的数。
表示把
ai
a
i
改变成为
t
t
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的话把位置线段树上每一个包含
i
i
的区间全部增加一个节点减去一个节点
ai
a
i
,然后把
ai
a
i
改成
j
j
;
Q操作是重点:二分答案,在位置线段树上的区间找比二分出来的
mid
m
i
d
小的个数,如果小于
k
k
,则缩小,否则
left
l
e
f
t
增加。
整体二分写法:
二分答案区间,将询问与修改一起二分(分流)。
代码(树套树版)
#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;
}