zoukankan      html  css  js  c++  java
  • BZOJ3065 带插入区间K小值

    推荐学习WJMZBMR《重量平衡树和后缀平衡树在信息学奥赛中的应用》

    转自hzwer:

    在替罪羊树每个结点放一棵包含该子树所有结点的权值线段树,也就是平衡树套权值线段树

    1、由于外层是平衡树,那么就能实现插入一个结点:找到它的位置,在根到其路径上所有结点的线段树中插入这个值

    2、查询区间第K大:找到这个区间包含若干棵子树,拿出他们的根的权值线段树,一起做个二分

    3、修改与插入类似

    4、当外层平衡树失衡的时候重构之,将某个子树自下而上线段树合并

    然后就是考验数据结构的能力了QAQ

    由于内存不够,我们还需要回收垃圾,即对数组的重复使用

    自己又加了许多的备注

      1 #include<bits/stdc++.h>
      2 #define alpha 0.75
      3 using namespace std;
      4 const int N=7e4+10,M=1e7+10;
      5 int tmp,n,m,sz,ans,root;
      6 int v[N],dfn[N],rt[N],ls[N],rs[N];
      7 struct node{
      8     int l,r,s;
      9 }t[M];
     10 vector<int>rec,a,p;
     11 int L=0,R=70000;//所谓权值线段树即是将点的权值作为线段树的下标
     12 inline int newnode()
     13 {
     14     if(!rec.size())
     15     return ++sz;
     16     else{
     17         int k=rec.back();rec.pop_back();
     18         return k;
     19     }//循环利用 
     20 }
     21 void reclaim(int &x)
     22 {
     23     if(!x)return;
     24     rec.push_back(x);
     25     reclaim(t[x].l);reclaim(t[x].r);//清除权值线段树 
     26     t[x].s=0;x=0;
     27 }
     28 void insert(int &k,int l,int r,int pos,int f)
     29 {
     30     if(!k)k=newnode();
     31     if(l==r){t[k].s+=f;return;}
     32     int mid=l+r>>1;
     33     if(pos<=mid)insert(t[k].l,l,mid,pos,f);
     34     else insert(t[k].r,mid+1,r,pos,f);
     35     t[k].s=t[t[k].l].s+t[t[k].r].s;
     36     if(!t[k].s)reclaim(k);//如果这个大小没有数我们就将它回收利用 
     37 }
     38 void build(int &k,int l,int r)
     39 {
     40     if(l>r)return;
     41     if(l==r){
     42         k=dfn[l];
     43         insert(rt[k],L,R,v[k],1);//构造权值线段树 
     44         return;
     45     }
     46     int mid=l+r>>1;k=dfn[mid];
     47     build(ls[k],l,mid-1);build(rs[k],mid+1,r);
     48     for(int i=l;i<=r;++i)
     49     insert(rt[k],L,R,v[dfn[i]],1);//对每颗子树建权值线段树 
     50 }
     51 void del(int &x)
     52 {
     53     if(!x)return;
     54     reclaim(rt[x]);
     55     del(ls[x]);p.push_back(x);del(rs[x]);//清除每个点的权值线段树 
     56     x=0;
     57 }
     58 void rebuild(int &x)
     59 {
     60     del(x);int s1=p.size();
     61     for(int i=1;i<=s1;++i)
     62     dfn[i]=p[i-1];//中序遍历后将值重新分配
     63     build(x,1,s1);//暴力重构 
     64     p.clear();
     65 }
     66 int modify(int k,int x,int w)
     67 {
     68     insert(rt[k],L,R,w,1);//修改路径上每颗子树 
     69     int LS=t[rt[ls[k]]].s,last;
     70     if(LS+1==x){last=v[k];v[k]=w;}
     71     else if(LS>=x)last=modify(ls[k],x,w);
     72     else last=modify(rs[k],x-LS-1,w);
     73     insert(rt[k],L,R,last,-1);//将原来的删去 
     74     return last;
     75 }
     76 void get(int k,int l,int r)//此时l,r不同于平时的区间而是指的是在k的线段树中大小为l~r这一段 
     77 {
     78     int LS=t[rt[ls[k]]].s,SUM=t[rt[k]].s;
     79     if(l==1&&r==SUM)//如果指的整颗子树
     80     {a.push_back(rt[k]);return;} 
     81     if(l<=LS+1&&r>=LS+1)p.push_back(v[k]);//如果单独是这一个点
     82     if(r<=LS)get(ls[k],l,r);
     83     else if(l>LS+1)get(rs[k],l-LS-1,r-LS-1);
     84     else{//分跨两边,此时中间点已经拿走 
     85         if(l<=LS)get(ls[k],l,LS);
     86         if(SUM>LS+1)get(rs[k],1,r-LS-1); 
     87     } 
     88 }
     89 int query(int l,int r,int k)
     90 {
     91     get(root,l,r);//找出这区间中的所有子树
     92     int s1=a.size(),s2=p.size();k--;
     93     l=L,r=R;
     94     while(l<r)
     95     {
     96         int mid=l+r>>1,sum=0;
     97         for(int i=0;i<s1;++i)sum+=t[t[a[i]].l].s;
     98         for(int i=0;i<s2;++i)
     99         if(p[i]>=l&&p[i]<=mid)sum++;
    100         if(sum>k){
    101             for(int i=0;i<s1;++i)a[i]=t[a[i]].l;
    102             r=mid;
    103         }
    104         else{
    105             for(int i=0;i<s1;++i)a[i]=t[a[i]].r;
    106             l=mid+1;k-=sum;
    107         }
    108     }
    109     a.clear();p.clear();
    110     return l;
    111 }
    112 void insert(int &k,int x,int w)
    113 {
    114     if(!k)
    115     {
    116         k=++n;
    117         insert(rt[k],L,R,w,1);
    118         v[k]=w;
    119         return;
    120     }
    121     insert(rt[k],L,R,w,1);
    122     int LS=t[rt[ls[k]]].s;
    123     if(LS>=x)insert(ls[k],x,w);
    124     else insert(rs[k],x-LS-1,w);
    125     if(t[rt[k]].s*alpha>max(t[rt[ls[k]]].s,t[rt[rs[k]]].s))//满足
    126     {
    127         if(tmp)
    128         {
    129             if(ls[k]==tmp)rebuild(ls[k]);
    130             else rebuild(rs[k]);
    131             tmp=0;
    132         }
    133     }
    134     else tmp=k;//不满足 
    135 }
    136 int main()
    137 {
    138     scanf("%d",&n);
    139     for(int i=1;i<=n;++i)scanf("%d",&v[i]);
    140     for(int i=1;i<=n;++i)dfn[i]=i;
    141     build(root,1,n);//构造替罪羊树
    142     scanf("%d",&m);char ch[10];int x,y,k;
    143     for(int i=1;i<=m;++i)
    144     {
    145         scanf("%s",ch);
    146         scanf("%d%d",&x,&y);x^=ans;y^=ans;
    147         if(ch[0]=='Q')
    148         {
    149             scanf("%d",&k);k^=ans;
    150             ans=query(x,y,k);printf("%d
    ",ans);
    151         }
    152         else if(ch[0]=='M')
    153         {
    154             modify(root,x,y);
    155         }
    156         else
    157         {
    158             tmp=0;insert(root,x-1,y);
    159             if(tmp){tmp=0;rebuild(root);}//重构整颗树 
    160         }
    161     }
    162     return 0;
    163 }
  • 相关阅读:
    traceroute工具
    tcpdump抓包
    Linux 信号表 signals
    Bloom Filter (海量数据处理)
    socks v5 协议解析
    Vim插件推荐
    建堆复杂度O(n)证明
    使用Vundle管理Vim插件
    VB调用C# dll
    域PC脱域
  • 原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8366494.html
Copyright © 2011-2022 走看看