题目
Satisfied
题解:与主席树前缀和的思想一致,树状数组维护一个"主席树"(不是前缀和那样的前i颗权值线段树的和 而是low(i)颗权值线段树的和 )平常一个主席树root[i]是[1,i]的和。现在是[i-low(i)+1,i]的和。
输入样例#1:
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
输出样例#1:
3
6
说明
对于所有数据,m,n≤100000
请注意常数优化,但写法正常的整体二分和树套树都可以大约1000ms每个点的时间过。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define low(a) a&-a
#define m(a,b) memset(a,b,sizof a)
#define en '\n'
using namespace std;
typedef long long ll;
const int N=2e5+5,M=N;
int a[N],refl[N],tot,n,m;
int sum[N*500],root[N],bit1[N],bit2[N],sz;
struct Query{int opt,l,r,k;}q[M];
struct tree{int l,r;}t[N*500];
void update(int &x,int wh,int l,int r,int val)
{
if(!x)
x=++sz;
sum[x]+=val;
if(l==r)
return;
int mid=(l+r)>>1;
if(wh<=mid)
update(t[x].l,wh,l,mid,val);
else
update(t[x].r,wh,mid+1,r,val);
}
void modify(int pos,int val)
{
int dex=lower_bound(refl+1,refl+tot+1,a[pos])-refl;
int i=pos;
while(i<=n)
{
update(root[i],dex,1,tot,val);
i+=low(i);
}
}
int query(int o1,int o2,int l,int r,int k)
{
if(l==r)
return l;
int left=0;
for(int i=1;i<=o1;i++)
left-=sum[t[bit1[i]].l];
for(int i=1;i<=o2;i++)
left+=sum[t[bit2[i]].l];
int mid=(l+r)>>1;
if(left>=k)
{
for(int i=1;i<=o1;i++)
bit1[i]=t[bit1[i]].l;
for(int i=1;i<=o2;i++)
bit2[i]=t[bit2[i]].l;
return query(o1,o2,l,mid,k);
}
else
{
for(int i=1;i<=o1;i++)
bit1[i]=t[bit1[i]].r;
for(int i=1;i<=o2;i++)
bit2[i]=t[bit2[i]].r;
return query(o1,o2,mid+1,r,k-left);
}
}
int getans(int l,int r,int k)
{
int o1=0,o2=0;
for(int i=l-1;i;i-=low(i))
bit1[++o1]=root[i];
for(int i=r;i;i-=low(i))
bit2[++o2]=root[i];
return query(o1,o2,1,tot,k);
}
int main()
{
sz=0;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),refl[i]=a[i];
tot=n;char s[3];
for(int i=1;i<=m;i++)
{
scanf("%s",s);
if(s[0]=='Q')
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k),q[i].opt=1;
else
scanf("%d%d",&q[i].l,&q[i].k),q[i].opt=2,refl[++tot]=q[i].k;
}
sort(refl+1,refl+tot+1);
tot=unique(refl+1,refl+tot+1)-(refl+1);
for(int i=1;i<=n;i++)
modify(i,1);
for(int i=1;i<=m;i++)
{
if(q[i].opt==1)
printf("%d\n",refl[getans(q[i].l,q[i].r,q[i].k)]);
else
{
modify(q[i].l,-1);
a[q[i].l]=q[i].k;
modify(q[i].l,1);
}
}
}
还可以 带修莫队+对权值分块(因为更改好多次,查询只有m次) :待补(2天之内)
还可以 二分答案ans+分块求询问区间内<ans的个数 小于k的最大值 : 待补(2天之内)
还可以 整体二分:不会 (待补 随缘)
权值线段树(外)+区间线段树(内) 妥妥的TLE。(T_T)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define foru(i,a,b) for(int i=a;i<=b;++i)
#define m(a,b) memset(a,b,sizof a)
#define en '\n'
using namespace std;
typedef long long ll;
const int N=2e5+5,M=1e5+5;
template<class T>void rd(T &x)
{
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
int a[N>>1],refl[N],tot,n,m;
struct Query{int l,r,c;}q[N];
struct tree{int l,r;}t[N*500];
int root[N*40],sum[N*500],sz;
void in_span(int &x,int d,int val,int l,int r)
{
if(!x) x=++sz;
if(l==r)
{
sum[x]+=val;
return;
}
int mid=(l+r)>>1;
if(d<=mid) in_span(t[x].l,d,val,l,mid);
else in_span(t[x].r,d,val,mid+1,r);
sum[x]=sum[t[x].l]+sum[t[x].r];
}
void out_point(int wh,int val,int d,int l,int r,int pos)
{
in_span(root[pos],d,val,1,n);
if(l==r)
return;
int mid=(l+r)>>1;
if(wh<=mid)
out_point(wh,val,d,l,mid,pos<<1);
else
out_point(wh,val,d,mid+1,r,pos<<1|1);
}
int in_query(int x,int cl,int cr,int l,int r)
{
if(cl<=l&r<=cr) return sum[x];
int mid=(l+r)>>1,ans=0;
if(cl<=mid) ans+=in_query(t[x].l,cl,cr,l,mid);
if(cr>mid) ans+=in_query(t[x].r,cl,cr,mid+1,r);
return ans;
}
int out_query(int nl,int nr,int l,int r,int pos,int k)
{
if(l==r)
return l;
int mid=(l+r)>>1,leftsum=0;
if(root[pos<<1])
leftsum=in_query(root[pos<<1],nl,nr,1,n);
if(leftsum>=k)
return out_query(nl,nr,l,mid,pos<<1,k);
else
return out_query(nl,nr,mid+1,r,pos<<1|1,k-leftsum);
}
int main()
{
rd(n),rd(m);
foru(i,1,n) rd(a[i]),refl[i]=a[i];
sort(refl+1,refl+n+1);
tot=n;
foru(i,1,m)
{
char ch[3];scanf("%s",ch);
if(ch[0]=='Q')
rd(q[i].l),rd(q[i].r),rd(q[i].c);
else
rd(q[i].l),rd(q[i].c),refl[++tot]=q[i].c;
}
sort(refl+1,refl+tot+1);
tot=unique(refl+1,refl+tot+1)-(refl+1);
foru(i,1,n)
{
a[i]=lower_bound(refl+1,refl+tot+1,a[i])-refl;
out_point(a[i],1,i,1,tot,1);
}
foru(i,1,m)
{
if(!q[i].r)
{
out_point(a[q[i].l],-1,q[i].l,1,tot,1);
a[q[i].l]=lower_bound(refl+1,refl+tot+1,q[i].c)-refl;
out_point(a[q[i].l],1,q[i].l,1,tot,1);
}
else printf("%d\n",refl[out_query(q[i].l,q[i].r,1,tot,1,q[i].c)]);
}
}