刚了一下午的主席树,基本熟悉两种经典操作
一.维护区间第k小值;
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=200010;
int n,q,m,cnt=0;
int a[N],b[N],T[N];
int sum[N<<5],L[N<<5],R[N<<5];
int build(int l,int r)
{
int rt=++cnt;
if(l<r)
{
int mid=(l+r)/2;
L[rt]=build(l,mid);
R[rt]=build(mid+1,r);
}
return rt;
}
int updata(int l,int r,int pre,int x)
{
int rt=++cnt;
L[rt]=L[pre];
R[rt]=R[pre];
sum[rt]=sum[pre]+1;
if(l<r)
{
int mid=(l+r)/2;
if(x<=mid)
L[rt]=updata(l,mid,L[pre],x);
else
R[rt]=updata(mid+1,r,R[pre],x);
}
return rt;
}
int query(int l,int r,int l1,int r1,int k)
{
if(l==r)
return l;
int x=sum[L[r1]]-sum[L[l1]];
int mid=(l+r)/2;
if(x>=k)
return query(l,mid,L[l1],L[r1],k);
else
return query(mid+1,r,R[l1],R[r1],k-x);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
m=unique(b+1,b+1+n)-b-1;
T[0]=build(1,m);
for(int i=1;i<=n;i++)
{
int t=lower_bound(b+1,b+1+m,a[i])-b;
T[i]=updata(1,m,T[i-1],t);
}
for(int i=1;i<=q;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
int t=query(1,m,T[x-1],T[y],z);
printf("%d\n",b[t]);
}
return 0;
}
二.支持单点修改,维护区间第k小值(树状数组套主席树)
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct question
{
int judge;
int t,p;
int x,y,z;
}linker[100001];
struct charman_tree
{
int val;
int l;
int r;
}tr[4001000];
int n,m,q,tot,cnt1,cnt2,x,y,z;
int a[100010],b[100010],T[100010];
int temp[3][20];
char opt;
void updata(int &node,int l,int r,int x,int val)
{
if(!node)
node=++tot;
tr[node].val+=val;
if(l==r)
return;
int mid=(l+r)/2;
if(x<=mid)
updata(tr[node].l,l,mid,x,val);
else
updata(tr[node].r,mid+1,r,x,val);
}
void add(int loc,int val)
{
int k=lower_bound(b+1,b+1+m,a[loc])-b;
for(int i=loc;i<=n;i+=i&-i)
updata(T[i],1,m,k,val);
}
int query(int l,int r,int k)
{
if(l==r)
return l;
int mid=(l+r)/2,sum=0;
for(int i=1;i<=cnt1;i++)
sum-=tr[tr[temp[1][i]].l].val;
for(int i=1;i<=cnt2;i++)
sum+=tr[tr[temp[2][i]].l].val;
if(k<=sum)
{
for(int i=1;i<=cnt1;i++)
temp[1][i]=tr[temp[1][i]].l;
for(int i=1;i<=cnt2;i++)
temp[2][i]=tr[temp[2][i]].l;
return query(l,mid,k);
}
else
{
for(int i=1;i<=cnt1;i++)
temp[1][i]=tr[temp[1][i]].r;
for(int i=1;i<=cnt2;i++)
temp[2][i]=tr[temp[2][i]].r;
return query(mid+1,r,k-sum);
}
}
int ask(int x,int y,int z)
{
memset(temp,0,sizeof(temp));
cnt1=cnt2=0;
for(int i=x-1;i>0;i-=i&-i)
temp[1][++cnt1]=T[i];
for(int i=y;i>0;i-=i&-i)
temp[2][++cnt2]=T[i];
return query(1,m,z);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[++m]=a[i];
}
for(int i=1;i<=q;i++)
{
cin>>opt;
if(opt=='C')
{
scanf("%d%d",&x,&y);
linker[i].judge=1;
linker[i].p=x;
linker[i].t=y;
b[++m]=y;
}
else
{
scanf("%d%d%d",&x,&y,&z);
linker[i].judge=2;
linker[i].x=x;
linker[i].y=y;
linker[i].z=z;
}
}
sort(b+1,b+1+m);
m=unique(b+1,b+1+m)-b-1;
for(int i=1;i<=n;i++)
add(i,1);
for(int i=1;i<=q;i++)
{
if(linker[i].judge==1)
{
int x=linker[i].p;
add(x,-1);
a[x]=linker[i].t;
add(x,1);
}
else
{
int t=ask(linker[i].x,linker[i].y,linker[i].z);
printf("%d\n",b[t]);
}
}
return 0;
}
查询区间众数
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 500010;
int n,q,m,cnt=0,ans,l,r,k;
int a[N],b[N],root[N];
int sum[N<<5],L[N<<5],R[N<<5];
int build(int l,int r)
{
int rt=++cnt;
int mid=(l+r)/2;
if(l<r)
{
L[rt]=build(l,mid);
R[rt]=build(mid+1,r);
}
return rt;
}
int update(int l,int r,int pre,int x)
{
int rt=++cnt;
L[rt]=L[pre];
R[rt]=R[pre];
sum[rt]=sum[pre]+1;
if(l<r)
{
int mid=(l+r)/2;
if(x<=mid)
L[rt]=update(l,mid,L[pre],x);
else
R[rt]=update(mid+1,r,R[pre],x);
}
return rt;
}
int query(int l,int r,int l1,int r1,int k)
{
if(l==r)
return l;
int mid=(l+r)/2;
int L1=L[r1],L2=L[l1];
if(sum[L1]-sum[L2]>k)
return query(l,mid,L2,L1,k);
int R1=R[r1],R2=R[l1];
if(sum[R1]-sum[R2]>k)
return query(mid+1,r,R2,R1,k);
return 0;
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
m=unique(b+1,b+1+n)-b-1;
root[0]=build(1,m);
for(int i=1;i<=n;i++)
{
int t=lower_bound(b+1,b+1+m,a[i])-b;
root[i]=update(1,m,root[i-1],t);
}
for(int i=1;i<=q;i++)
{
scanf("%d%d",&l,&r);
int k=(r-l+1)/2;
printf("%d\n",query(1,m,root[l-1],root[r],k));
}
return 0;
}