动态主席树
P2617 Dynamic Rankings
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int n,m,a[maxn],b[maxn*2],total;
int ST[maxn*300],ls[maxn*300],rs[maxn*300],no,root[maxn];
int ql[20],qr[20],cnt1,cnt2;
struct Opt
{
int l,r,k,x,y;
int tag;
}opt[maxn];
inline int lowbit(int x)
{
return x&(-x);
}
void Update(int &rt,int pos,int L,int R,int val)
{
if(!rt)
rt=++no;
ST[rt]+=val;
if(L==R)
return;
int mid=(L+R)>>1;
if(pos<=mid)
Update(ls[rt],pos,L,mid,val);
if(pos>mid)
Update(rs[rt],pos,mid+1,R,val);
}
void add(int x,int val)
{
int pos=lower_bound(b+1,b+1+total,a[x])-b;
for(int i=x;i<=n;i+=lowbit(i))
Update(root[i],pos,1,total,val);
}
int Query(int L,int R,int k)
{
if(L==R)
return L;
int sum=0;
for(int i=1;i<=cnt1;++i)
sum-=ST[ls[ql[i]]];
for(int i=1;i<=cnt2;++i)
sum+=ST[ls[qr[i]]];
int mid=(L+R)>>1;
if(k-sum<=0)
{
for(int i=1;i<=cnt1;++i)
ql[i]=ls[ql[i]];
for(int i=1;i<=cnt2;++i)
qr[i]=ls[qr[i]];
return Query(L,mid,k);
}
else
{
for(int i=1;i<=cnt1;++i)
ql[i]=rs[ql[i]];
for(int i=1;i<=cnt2;++i)
qr[i]=rs[qr[i]];
return Query(mid+1,R,k-sum);
}
}
int PreQuery(int l,int r,int k)
{
cnt1=0,cnt2=0;
for(int i=l;i>0;i-=lowbit(i))
ql[++cnt1]=root[i];
for(int i=r;i>0;i-=lowbit(i))
qr[++cnt2]=root[i];
return Query(1,total,k);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
int cnt=n;
for(int i=1;i<=m;++i)
{
char op[10];
scanf("%s",op);
if(op[0]=='Q')
{
scanf("%d%d%d",&opt[i].l,&opt[i].r,&opt[i].k);
opt[i].tag=1;
}
else
{
scanf("%d%d",&opt[i].x,&opt[i].y);
opt[i].tag=0;
b[++cnt]=opt[i].y;
}
}
sort(b+1,b+1+cnt);
total=unique(b+1,b+1+cnt)-b-1;
for(int i=1;i<=n;++i)
add(i,1);
for(int i=1;i<=m;++i)
{
if(!opt[i].tag)
{
add(opt[i].x,-1);
a[opt[i].x]=opt[i].y;
add(opt[i].x,1);
}
else
{
int pos=PreQuery(opt[i].l-1,opt[i].r,opt[i].k);
printf("%d\n",b[pos]);
}
}
return 0;
}
动态主席树就是构建n棵权值线段树,每棵树理论上会有total个节点。但其实只需要关注属于自己的一条路径就可以了。当然第x棵树上还是会有前面的节点更新过来的节点。
然后用树状数组去关联这n棵线段树。
add:每次修改一棵线段树x,都要给x~n中相关联的做Update操作
Update:根据节点的位置给途中遇到的每个节点做更新
Query:每次查询前,处理好下一层需要访问的根节点,之后才能继续往下走
H. Yuuki and a problem
离散化
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10;
int n,q,total;
int a[maxn],b[maxn*2];
ll ST[maxn*150];
int ls[maxn*150],rs[maxn*150],root[maxn],no;
int cnt1,cnt2,ql[20][20],qr[20][20];
struct Opt
{
int l,r;
int tag;
}opt[maxn];
inline int lowbit(int x)
{
return x&(-x);
}
void Update(int &rt,int pos,int L,int R,int val)
{
if(!rt)
rt=++no;
ST[rt]+=val;
if(L==R)
return;
int mid=(L+R)>>1;
if(pos<=mid)
Update(ls[rt],pos,L,mid,val);
if(pos>mid)
Update(rs[rt],pos,mid+1,R,val);
}
void add(int x,int val)
{
int pos=lower_bound(b+1,b+1+total,a[x])-b;
for(int i=x;i<=n;i+=lowbit(i))
Update(root[i],pos,1,total,val);
}
ll Query(int l,int r,int L,int R,int d)
{
if(l<=L&&R<=r)
{
ll ans=0;
for(int i=1;i<=cnt1;++i)
ans-=ST[ql[d][i] ];
for(int i=1;i<=cnt2;++i)
ans+=ST[qr[d][i] ];
return ans;
}
int mid=(L+R)>>1;
ll ans=0;
if(l<=mid)
{
for(int i=1;i<=cnt1;++i)
ql[d+1][i]=ls[ql[d][i]];
for(int i=1;i<=cnt2;++i)
qr[d+1][i]=ls[qr[d][i]];
ans+=Query(l,r,L,mid,d+1);
}
if(r>mid)
{
for(int i=1;i<=cnt1;++i)
ql[d+1][i]=rs[ql[d][i]];
for(int i=1;i<=cnt2;++i)
qr[d+1][i]=rs[qr[d][i]];
ans+=Query(l,r,mid+1,R,d+1);
}
return ans;
}
ll PreQuery(int l,int r,int pos)
{
memset(ql,0,sizeof(ql));
memset(qr,0,sizeof(qr));
cnt1=cnt2=0;
for(int i=l;i>0;i-=lowbit(i))
ql[1][++cnt1]=root[i];
for(int i=r;i>0;i-=lowbit(i))
qr[1][++cnt2]=root[i];
return Query(1,pos,1,total,1);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
int cnt=n;
for(int i=1;i<=q;++i)
{
int op;
scanf("%d",&op);
if(op==1)
{
opt[i].tag=1;
scanf("%d%d",&opt[i].l,&opt[i].r);
b[++cnt]=opt[i].r;
}
else
{
opt[i].tag=2;
scanf("%d%d",&opt[i].l,&opt[i].r);
}
}
sort(b+1,b+1+cnt);
total=unique(b+1,b+1+cnt)-b-1;
for(int i=1;i<=n;++i)
add(i,a[i]);
for(int i=1;i<=q;++i)
{
if(opt[i].tag==1)
{
int x=opt[i].l,y=opt[i].r;
add(x,-a[x]);
a[x]=y;
add(x,a[x]);
}
else
{
ll x=0,y=0;
while(1)
{
y=x+1;
int pos=upper_bound(b+1,b+1+total,y)-b-1;
x=PreQuery(opt[i].l-1,opt[i].r,pos);
if(x<y)
break;
}
printf("%lld\n",x+1);
}
}
return 0;
}
非离散化
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10;
int n,q,total=2e5;
int a[maxn],b[maxn*2];
ll ST[maxn*150];
int ls[maxn*150],rs[maxn*150],root[maxn],no;
int cnt1,cnt2,ql[20][20],qr[20][20];
inline int lowbit(int x)
{
return x&(-x);
}
void Update(int &rt,int pos,int L,int R,int val)
{
if(!rt)
rt=++no;
ST[rt]+=val;
if(L==R)
return;
int mid=(L+R)>>1;
if(pos<=mid)
Update(ls[rt],pos,L,mid,val);
if(pos>mid)
Update(rs[rt],pos,mid+1,R,val);
}
void add(int x,int pos,int val)
{
for(int i=x;i<=n;i+=lowbit(i))
Update(root[i],pos,1,total,val);
}
ll Query(int l,int r,int L,int R,int d)
{
if(l<=L&&R<=r)
{
ll ans=0;
for(int i=1;i<=cnt1;++i)
ans-=ST[ql[d][i]];
for(int i=1;i<=cnt2;++i)
ans+=ST[qr[d][i]];
return ans;
}
int mid=(L+R)>>1;
ll ans=0;
if(l<=mid)
{
for(int i=1;i<=cnt1;++i)
ql[d+1][i]=ls[ql[d][i]];
for(int i=1;i<=cnt2;++i)
qr[d+1][i]=ls[qr[d][i]];
ans+=Query(l,r,L,mid,d+1);
}
if(r>mid)
{
for(int i=1;i<=cnt1;++i)
ql[d+1][i]=rs[ql[d][i]];
for(int i=1;i<=cnt2;++i)
qr[d+1][i]=rs[qr[d][i]];
ans+=Query(l,r,mid+1,R,d+1);
}
return ans;
}
ll PreQuery(int l,int r,int pos)
{
memset(ql,0,sizeof(ql));
memset(qr,0,sizeof(qr));
cnt1=cnt2=0;
for(int i=l;i>0;i-=lowbit(i))
ql[1][++cnt1]=root[i];
for(int i=r;i>0;i-=lowbit(i))
qr[1][++cnt2]=root[i];
return Query(1,pos,1,total,1);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
add(i,a[i],a[i]);
}
while(q--)
{
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==1)
{
add(l,a[l],-a[l]);
a[l]=r;
add(l,a[l],a[l]);
}
else
{
ll x=0,y=0;
while(1)
{
y=x+1;
x=PreQuery(l-1,r,min(1ll*total,y));
if(x<y)
break;
}
printf("%lld\n",x+1);
}
}
return 0;
}