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);
}
}
}
樹狀數組其實很有用,也不是很難(的樣子。。)