Luogu P2617 Dynamic Rankings
主席树真的比树链剖分友善很多TuT
解法:主席树+树状数组
弄一个树状数组
这个样子
每一个格子(C开头那些)维护一棵主席树中的线段树(大概是这个意思吧!)
修改时要注意!!
如果把树状数组比作老板和员工,
那么 x+lowbit(x) 表示的就是比 x 高一级的他的上司,
x-lowbit(x) 表示的就是编号在 x 前的第一个不是 x 的下属的人。
#include<cstdio>
#include<cstring>
int a[2000100],b[2000100],root[2000100];
int len=0,n,m,note=0;
struct nod1{int l,r,c,lc,rc;}tr[40001000];
//空间要开够!
int lowbit(int x)
{
return x & -x;
}//玄学lowbit
void update(int &rt,int l,int r,int x)
{
if(rt==0)
{
len++;rt=len;
//少什么才建什么
}
tr[rt].c+=note;
//note是1时是添加
//note是-1时是删除
//以此区分
if(l==r)return ;
int mid=(l+r)/2;
if(x<=mid)update(tr[rt].lc,l,mid,x);
else update(tr[rt].rc,mid+1,r,x);
}
void change(int x,int k)
{
note=-1;
for(int i=x;i<=n;i+=lowbit(i))
update(root[i],0,1e9,a[x]);
//把所有有累计x的都--
a[x]=k;
note=1;
for(int i=x;i<=n;i+=lowbit(i))
update(root[i],0,1e9,k);
//添加
}
int find(int x,int y,int l,int r,int k)
{
x-=1;
int numx=0,numy=0;
int familyy[10010],familyx[10010];
//与y有关的所有格子,与x有关的所有格子
//后称“家族 ”
for(int i=x;i>=1;i-=lowbit(i))
{
numx++;familyx[numx]=root[i];
}
//记录
for(int i=y;i>=1;i-=lowbit(i))
{
numy++;familyy[numy]=root[i];
}
while(l<r)
//二分寻找Kth
{
int g=0;
int mid=(l+r)/2;
for(int i=1;i<=numy;i++)
g+=tr[tr[familyy[i]].lc].c;
//把y家族的左儿子所掌管的数量全部加起来才是1~y的数量
for(int i=1;i<=numx;i++)
g-=tr[tr[familyx[i]].lc].c;
//同理,加起来才是1~(x-1)左儿子所掌管的数量
//剪了才是x~y区间的
if(k<=g)
{
for(int i=1;i<=numx;i++)
familyx[i]=tr[familyx[i]].lc;
//把家族向左边移去
for(int i=1;i<=numy;i++)
familyy[i]=tr[familyy[i]].lc;
r=mid;
}
else
{
for(int i=1;i<=numx;i++)
familyx[i]=tr[familyx[i]].rc;
//向右移
for(int i=1;i<=numy;i++)
familyy[i]=tr[familyy[i]].rc;
l=mid+1;k-=g;
}
}
return r;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
note=1;
for(int j=i;j<=n;j+=lowbit(j))
update(root[j],0,1e9,a[i]);
//像静态主席树插入那样
//树状数组中所有有关系的格子都要++
}
for(int i=1;i<=m;i++)
{
char ss[10];
int k,x,y;
scanf("%s",ss+1);
if(ss[1]=='Q')
{
scanf("%d %d %d",&x,&y,&k);
printf("%d\n",find(x,y,0,1e9,k));
}
else
{
scanf("%d %d",&x,&k);
change(x,k);
}
}
}
树状数组其实很有用,也不是很难(的样子。。)