您的位置:首页 > 其它

【BZOJ】1901: Zju2112 Dynamic Rankings

2017-08-21 11:30 232 查看

【题意】带修改的查询区间第k小

【算法】树状数组套可持久化线段树

【题解】对于树状数组上的每个节点,维护可持久化权值线段树(节点为权值),从而达到查询前缀和的目的。

对于每次修改,在待修改线段树基础上运用可持久化性质来修改,先删除原数字,再加入新数字

注意记录修改后的原数字,方便后来删除。

★注意区分权值范围和数组范围的区别!!!

复杂度O(n log2n)。

注意点全部标注在代码中,细节巨多。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
using namespace std;
int read()
{
char c;int s=0,t=1;
while(!isdigit(c=getchar()))if(c=='-')t=-1;
do{s=s*10+c-'0';}while(isdigit(c=getchar()));
return s*t;
}
const int maxn=10010;
struct tree{int l,r,sum;}t[10000010];//空间开大!!!100w都过不去啊。。。
char s[10];
int cnt1,cnt2,a1[maxn],a2[maxn],a[maxn],b1[maxn],b2[maxn],b3[maxn],n,m,root[maxn],tot,c[maxn*2],sz=0;

void insert(int l,int r,int x,int &y,int v,int c){
y=++sz;//设置新节点!!!
t[y]=t[x];t[y].sum+=c;
if(l==r)return;
int mid=(l+r)>>1;
if(v<=mid)insert(l,mid,t[x].l,t[y].l,v,c);
else insert(mid+1,r,t[x].r,t[y].r,v,c);
}
int ask(int l,int r,int v){
if(l==r)return l;
int sum=0;
for(int i=1;i<=cnt1;i++)sum-=t[t[a1[i]].l].sum;
for(int i=1;i<=cnt2;i++)sum+=t[t[a2[i]].l].sum;
int mid=(l+r)>>1;
if(sum>=v){
for(int i=1;i<=cnt1;i++)a1[i]=t[a1[i]].l;
for(int i=1;i<=cnt2;i++)a2[i]=t[a2[i]].l;
return ask(l,mid,v);
}
else{
for(int i=1;i<=cnt1;i++)a1[i]=t[a1[i]].r;
for(int i=1;i<=cnt2;i++)a2[i]=t[a2[i]].r;
return ask(mid+1,r,v-sum);//转入右边要减去左边的
}
}

int lowbit(int x){return x&(-x);}
void modify(int x,int k,int p){for(int i=x;i<=n;i+=lowbit(i))insert(1,tot,root[i],root[i],k,p);}
//分清,tot是权值线段树范围,n是数组范围
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
a[i]=read();
c[++tot]=a[i];
}
for(int i=1;i<=m;i++){
scanf("%s%d%d",s,&b1[i],&b2[i]);
if(s[0]=='Q')b3[i]=read();
else c[++tot]=b2[i];
}
sort(c+1,c+tot+1);
tot=unique(c+1,c+tot+1)-c-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(c+1,c+tot+1,a[i])-c;
for(int i=1;i<=m;i++)if(!b3[i])b2[i]=lower_bound(c+1,c+tot+1,b2[i])-c;
for(int i=1;i<=n;i++)modify(i,a[i],1);
for(int i=1;i<=m;i++){
if(b3[i]){
cnt1=0;cnt2=0;
for(int j=b1[i]-1;j>=1;j-=lowbit(j))a1[++cnt1]=root[j];
for(int j=b2[i];j>=1;j-=lowbit(j))a2[++cnt2]=root[j];//用根啊老铁
printf("%d\n",c[ask(1,tot,b3[i])]);//询问给的是离散化后的值,要还原
}
else{
modify(b1[i],a[b1[i]],-1);
a[b1[i]]=b2[i];
modify(b1[i],b2[i],1);
}
}
return 0;
}
View Code

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: