C96 树状数组套权值线段树 P2617 Dynamic Rankings

视频链接:C96 树状数组套权值线段树 P2617 Dynamic Rankings_哔哩哔哩_bilibili

 

 

 

 

C50【模板】可持久化线段树(主席树)P3834 静态区间第 k 小
C84 树状数组套权值线段树 P3157 [CQOI2011] 动态逆序对
Luogu P2617 Dynamic Rankings

// 树状数组 套 权值线段树树 O(nlognlogn)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=100005;
#define lowb(x) x&-x
#define mid ((l+r)>>1)
int n,m,num,a[N],b[N<<1],c[N],d[N],e[N];
int tot,rt[N],sum[N*400],ls[N*400],rs[N*400];
int n1,n2,rt1[N],rt2[N]; //记录查询路径上的logn个根

void change2(int &u,int l,int r,int p,int k){ //内修
  if(!u) u=++tot;
  sum[u]+=k;
  if(l==r) return;
  if(p<=mid) change2(ls[u],l,mid,p,k);
  else change2(rs[u],mid+1,r,p,k);
}
void change1(int x,int k){ //外修
  int p=lower_bound(b+1,b+1+num,a[x])-b;
  while(x<=n) change2(rt[x],1,num,p,k), x+=lowb(x);
}
int query2(int l,int r,int k){ //内查
  if(l==r) return l;
  int s=0;
  //  计算两条查询路径上左子树的前缀和之差
  for(int i=1;i<=n1;++i) s-=sum[ls[rt1[i]]];
  for(int i=1;i<=n2;++i) s+=sum[ls[rt2[i]]];
  if(s>=k){ //前缀和之差>=k,说明区间第k小在左子树
    //  两条查询路径上的logn个线段树一起走到左子树
    for(int i=1;i<=n1;++i) rt1[i]=ls[rt1[i]];
    for(int i=1;i<=n2;++i) rt2[i]=ls[rt2[i]];
    return query2(l,mid,k);
  }
  else{     //前缀和之差 <k,说明区间第k小在右子树
    //  两条查询路径上的logn个线段树一起走到右子树
    for(int i=1;i<=n1;++i) rt1[i]=rs[rt1[i]];
    for(int i=1;i<=n2;++i) rt2[i]=rs[rt2[i]];
    return query2(mid+1,r,k-s);
  }
}
int query1(int x,int y,int k){ //外查
  n1=n2=0;
  while(x) rt1[++n1]=rt[x],x-=lowb(x); //左路径上的根
  while(y) rt2[++n2]=rt[y],y-=lowb(y); //右路径上的根
  return query2(1,num,k);
}
int main(){
  scanf("%d%d",&n,&m); char op[5];
  for(int i=1;i<=n;++i)scanf("%d",&a[i]),b[++num]=a[i];
  for(int i=1;i<=m;++i){
    scanf("%s",op);       //b数组记录原值a和修改值d
    if(op[0]=='Q') scanf("%d%d%d",&c[i],&d[i],&e[i]);
    else scanf("%d%d",&c[i],&d[i]),b[++num]=d[i];
  }
  sort(b+1,b+1+num); //离散化
  num=unique(b+1,b+1+num)-b-1; 
  for(int i=1;i<=n;++i) change1(i,1); //建树套树
  for(int i=1;i<=m;++i){
    if(e[i])printf("%d\n",b[query1(c[i]-1,d[i],e[i])]);
    else{
      change1(c[i],-1); //清除旧值贡献
      a[c[i]]=d[i];     //记录修改值
      change1(c[i],1);  //插入修改值贡献
    }
  }
}

 

posted @ 2024-01-18 09:08  董晓  阅读(172)  评论(0编辑  收藏  举报