• 二逼平衡树


    题目链接:https://www.luogu.org/problemnew/show/P3380

    这题解法真是多,各种数据结构的模板练习题啊。。(在此之前下面四个一个都不会)

    1. 查询k在区间内的排名

    2. 查询区间内排名为k的值

    3. 修改某一位值上的数值

    4. 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)

    5. 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

    1.线段树套平衡树

    对于线段树的每一个节点,开一颗splay,维护序列中的元素

    操作1,类似于线段树区间查询,查询在线段树的点的排名的和 nlognlogn

    操作2,二分答案 nlognlognlogn 

    由于每颗splay的形态不一定一样,所以他不能和线段树一样在树上二分

    看了别人代码学习来的,直接对数的大小进行二分,满足条件的最大数一定在数列上(刚开始还想着在splay上二分 就复杂多了)

    操作3. splay上插入删除 nlognlogn

    操作4(5同理).每颗splay上查找找最大值

    代码个人感觉如果splay和线段树模板打的熟是要比带修主席树好写的

    #include <bits/stdc++.h>
    using namespace std;
    #define mid (h+t)/2
    #define INF 1e9
    #define INF2 2147483647
    const int maxn=51111;
    const int maxn2=2111111;
    int a[maxn],count2[maxn2],leftson[maxn2],rightson[maxn2],
    fa[maxn2],root[maxn*4],data[maxn2],num,n,m;
    bool tt;
    struct re
    {
      int h,t;
    }p[maxn*4];  
    void updata(int x)
    {
      count2[x]=count2[leftson[x]]+count2[rightson[x]]+1;
    }
    void rotate(int x,int y)
    {
        int father=fa[x];
        if (y==1)
        {
            rightson[father]=leftson[x]; 
            if (leftson[x]) fa[leftson[x]]=father;
        } else
        {
            leftson[father]=rightson[x];
            if (rightson[x]) fa[rightson[x]]=father;
        }
        fa[x]=fa[father];
        if (fa[father])
        {
            if (leftson[fa[father]]==father)
              leftson[fa[father]]=x;
            else rightson[fa[father]]=x; 
        }
        fa[father]=x;
        if (y==1) leftson[x]=father; else rightson[x]=father;
        updata(father); updata(x);
    }
    void splay(int x,int goal,int z)
    {
        if (x==root[z]) return;
        int father;
        while (fa[x]!=goal)
        {
            father=fa[x];
            if (fa[father]==goal)
            {
                if (x==leftson[father]) rotate(x,2);
                else rotate(x,1);
            } else
            {
                if (father==leftson[fa[father]])
                {
                    if (x==leftson[father])
                      rotate(father,2),rotate(x,2);
                    else rotate(x,1),rotate(x,2);
                } else
                {
                    if (x==rightson[father])
                      rotate(father,1),rotate(x,1);
                    else rotate(x,2),rotate(x,1);
                }
            }  
        }
        if (goal==0) root[z]=x;
    }
    void insert2(int x,int y,int z)
    {
      while (x)
      {
        count2[x]++;
        if (y<data[x])
        {
          if (!leftson[x]) break;
          x=leftson[x];
        } else
        {
          if (!rightson[x]) break;
          x=rightson[x];
        }
      }
      data[++num]=y; fa[num]=x; count2[num]=1;
      if (x)
      { 
        if (y>=data[x]) rightson[x]=num; 
        else leftson[x]=num;
      }
      splay(num,0,z);
    }
    int query2(int x,int goal)
    {
      int ans=0;
      while (x)
      {
        if (data[x]==goal) tt=1;
        if (data[x]<goal) ans+=count2[leftson[x]]+1,x=rightson[x]; else
        x=leftson[x];
      }
      return(ans);
    }
    int search(int x,int goal)
    {
      while (x)
      {
        if (data[x]==goal) return(x);
        if (data[x]<goal) x=rightson[x];
        else x=leftson[x];
      }
    }
    void delete2(int number,int goal)
    {
      splay(goal,0,number);
      int x=leftson[goal];
      if (x==0)
      {
        root[number]=rightson[goal];
        fa[root[number]]=0; return;
      }
      while (rightson[x]) x=rightson[x];
      splay(x,goal,number);
      rightson[x]=rightson[goal];
      if (rightson[goal]) fa[rightson[goal]]=x;
      updata(x); fa[x]=0; root[number]=x;
    } 
    void build(int x,int h,int t)
    {
       p[x].h=h; p[x].t=t;
       for (int i=h;i<=t;i++) 
       insert2(root[x],a[i],x);
       if (h==t) return;
       build(x*2,h,mid); build(x*2+1,mid+1,t);
    }
    int query(int x,int h,int t,int goal)
    {
      if (p[x].h>t||p[x].t<h) return(0);
      if (h<=p[x].h&&p[x].t<=t)
      {
        return(query2(root[x],goal));
      }
      return(query(x*2,h,t,goal)+query(x*2+1,h,t,goal));
    }
    void delete1(int x,int pos,int goal)
    {
      int h=p[x].h,t=p[x].t;
      int y=search(root[x],goal);
      delete2(x,y); 
      if (h==t) return;
      if (pos<=mid) delete1(x*2,pos,goal); else delete1(x*2+1,pos,goal); 
    }
    void insert1(int x,int pos,int goal)
    {
      int h=p[x].h,t=p[x].t;
      insert2(root[x],goal,x); 
      if (h==t) return;
      if (pos<=mid) insert1(x*2,pos,goal); else insert1(x*2+1,pos,goal);
    }
    int k_th(int x,int y,int k)
    {
      int h=1,t=INF;
      while (h<t)
      {
        int midd=(h+t+1)/2; 
        if (1+query(1,x,y,midd)<=k) h=midd; else t=midd-1;
      }
      return(h);
    }
    int main()
    {
      freopen("noip.in","r",stdin);
      freopen("noip.out","w",stdout);
      cin>>n>>m;
      for (int i=1;i<=n;i++) cin>>a[i];
      build(1,1,n);
      int c,d,e,f;
      for (int i=1;i<=m;i++)
      {
        cin>>c;
        if (c==3) cin>>d>>e; else cin>>d>>e>>f;
        if (c==1)
        {
          cout<<query(1,d,e,f)+1<<endl;
        }
        if (c==2)
        {
          cout<<k_th(d,e,f)<<endl;
        }
        if (c==3)
        {
          delete1(1,d,a[d]);
          insert1(1,d,e);
          a[d]=e;
        }
        if (c==4)
        {
          int x=query(1,d,e,f)+1; 
          if (x==1) cout<<-INF2<<endl; else
          {
            cout<<k_th(d,e,x-1)<<endl;  
          } 
        }
        if (c==5)
        {
          tt=0;
          int x=query(1,d,e,f)+1;
          if (x==e-d+2-tt) cout<<INF2<<endl; else
          {
            cout<<k_th(d,e,x+tt)<<endl;
          }
        }
      }
      return 0;
    }

    似乎得卡常 洛谷不开o2tle

    2.cdq分治(并没有看懂以后再学吧,洛谷上有题解)

    3.树状数组套主席树

    第一维是树状数组,每个里面开一颗线段树(这个刚开始有点难理解,每个节点里维护的其实并不是任何东西的答案,是为了配合树状数组的使用)

    前3个操作就是基本操作吧

    对于4/5,计算出这个数的排名+-1再在树上二分就可以了

    但是允许元素不出现在原序列就导致5的判断很恶心了

    1.查找的时候如果出现在原数列那么是+1不然就是这个排名

    2.还有一个坑 就是检验是不是最后一个数时

    将这个数搞成离散化的数二分的时候 要注意它可能比最后一个数还要大 所以要特殊处理

    *从这个中注意到要注意二分查找的边界限制,显然这个程序中的二分是找到比它小的值,如果这个值比它大那么就要处理了

    *待修主席树的核心还是很好写的 然而这道题的细节就很不友善了

    说一下这一题代码的实现,离散化是数据结构常有的,核心部分很好写,把查询x的排名变为查询比x小的数有多少个再+1(写平衡树写多了很容易忘记这个)

    还有就是空间,(n+m)logn logn 事实我的代码开了100倍,讲道理最坏情况是要500倍左右

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 100000
    #define INF 2147483647
    int root[maxn],b[maxn],d[maxn],e[maxn],rea[maxn],cnt,num,n,m,lll;
    int tmp1[maxn],tmp2[maxn];
    bool tt;
    struct re
    {
        int a,b,c,d;
    }a[maxn],c[maxn],f[maxn];
    struct ree
    {
        int x,leftson,rightson;
    }p[maxn*50];
    bool cmp(re x,re y)
    {
              if (x.a<y.a) return(true); else return(false);
    }
    void updata(int x)
    {
        p[x].x=p[p[x].leftson].x+p[p[x].rightson].x;
    }
    #define mid (h+t)/2
    void change(int &x,int h,int t,int sum,int l)
    {
        if (!x)
        {
            x=++cnt;
        }
        p[x].x+=l;
        if (h==t) return;
        if (sum<=mid) change(p[x].leftson,h,mid,sum,l);
        else change(p[x].rightson,mid+1,t,sum,l);
        updata(x);
    }
    int query2(int x,int h,int t,int num)
    {
        if (x==0||h>num) return(0);
        if (t<num) return(p[x].x);
        return(query2(p[x].leftson,h,mid,num)+query2(p[x].rightson,mid+1,t,num));
    }
    #define lowbit(x) (x&-x)
    void insert(int x,int y,int l)
    {
        while (x<=n)
        {
            change(root[x],1,lll,y,l);
            x+=lowbit(x);
        }
    }
    int query(int x,int y)
    {
        int ans=0;
        while (x)
        {
            ans+=query2(root[x],1,lll,y);
            x-=lowbit(x);
        }
        return(ans);
    }
    struct ret
    {
        int a,c; bool b;
    };
    int find(int x)
    {
        int h=1,t=num;
        while (h<t)
        {
            if (f[mid].a<x) h=mid+1; else t=mid;
        }
        if (f[h].a==x) tt=1;
        if (f[h].a<x) return(f[h].d+1);
        else return(f[h].d);
    }
    int k_th(int x,int y,int z)
    {
        int num1=0,num2=0; x--;
        while (x)
        {
            tmp1[++num1]=root[x]; x-=lowbit(x);
      } 
      while (y)
      {
          tmp2[++num2]=root[y]; y-=lowbit(y);
        }
        int h=1,t=lll,tmp;
      while (h!=t)
      {
            tmp=0;
            for (int i=1;i<=num1;i++) tmp-=p[p[tmp1[i]].leftson].x;
            for (int i=1;i<=num2;i++) tmp+=p[p[tmp2[i]].leftson].x;
            if (tmp>=z)
            {
            t=mid;
                for (int i=1;i<=num1;i++) tmp1[i]=p[tmp1[i]].leftson;
                for (int i=1;i<=num2;i++) tmp2[i]=p[tmp2[i]].leftson;
              } else
              {
                  h=mid+1;z-=tmp;
                  for (int i=1;i<=num1;i++) tmp1[i]=p[tmp1[i]].rightson;
                  for (int i=1;i<=num2;i++) tmp2[i]=p[tmp2[i]].rightson;
              }
        }
        return (rea[h]);
    }
    bool check(int x,int y,int goal)
    {
        int num1=0,num2=0; x--;
        while (x)
        {
            tmp1[++num1]=root[x]; x-=lowbit(x);
      } 
      while (y)
      {
          tmp2[++num2]=root[y]; y-=lowbit(y);
        }
        int h=1,t=lll,tmp=0;
        while (h!=t)
        {
            if (goal<=mid)
            {
                 t=mid;
               for (int i=1;i<=num1;i++) tmp1[i]=p[tmp1[i]].leftson;
             for (int i=1;i<=num2;i++) tmp2[i]=p[tmp2[i]].leftson;
            } else
            {
                 h=mid+1;
               for (int i=1;i<=num1;i++) tmp1[i]=p[tmp1[i]].rightson;
               for (int i=1;i<=num2;i++) tmp2[i]=p[tmp2[i]].rightson;
            }
        }
         for (int i=1;i<=num1;i++) tmp-=p[tmp1[i]].x;
       for (int i=1;i<=num2;i++) tmp+=p[tmp2[i]].x;
       if (tmp) return(1); else return(0);
    }
    int main()
    {
          std::ios::sync_with_stdio(false); 
          freopen("noip.in","r",stdin);
          freopen("noip.out","w",stdout);
          cin>>n>>m;
          for (int i=1;i<=n;i++) cin>>a[i].a,f[i].a=a[i].a,f[i].b=i,f[i].c=0;
          num=n;
          for (int i=1;i<=m;i++)
          {
                cin>>b[i];
                if (b[i]==1) cin>>c[i].a>>d[i]>>e[i];
                if (b[i]==2) cin>>c[i].a>>d[i]>>e[i];
                if (b[i]==3)
                {
                    cin>>c[i].a>>d[i];
                    f[++num].a=d[i]; f[num].b=i;f[num].c=1;
                    }
                    if (b[i]==4) cin>>c[i].a>>d[i]>>e[i];
                    if (b[i]==5) cin>>c[i].a>>d[i]>>e[i];
            }
            sort(f+1,f+num+1,cmp); f[0].a=-INF;
            for (int i=1;i<=num;i++)
            {
                if (f[i].a!=f[i-1].a) lll++; f[i].d=lll; rea[lll]=f[i].a;
                if (f[i].c==0) a[f[i].b].b=lll,a[f[i].b].c=i;
                else c[f[i].b].b=lll,c[f[i].b].c=i;
            }
            //for (int i=1;i<=num;i++) cout<<f[i].a<<endl;
            for (int i=1;i<=n;i++)
            {
                insert(i,a[i].b,1);
            }
            for (int i=1;i<=m;i++)
            {
                if (b[i]==1)
                {
                    int x=find(e[i]);
                    cout<<1+query(d[i],x)-query(c[i].a-1,x)<<endl;  //zhuyi0
                }
                if (b[i]==2)
                {
                    cout<<k_th(c[i].a,d[i],e[i])<<endl; 
                }
                if (b[i]==3)
                {
              insert(c[i].a,a[c[i].a].b,-1);
              insert(c[i].a,c[i].b,1);
              a[c[i].a].b=c[i].b;
              } 
              if (b[i]==4)
              {
                  int x=find(e[i]);
                  int y=query(d[i],x)-query(c[i].a-1,x)+1;
                  if (y==1) cout<<-INF<<endl;
              else cout<<k_th(c[i].a,d[i],y-1)<<endl;
                }
                if (b[i]==5)
                {
                    tt=0;int x=find(e[i]);
                    if(tt==1&&check(c[i].a,d[i],x)) tt=1; else tt=0;
                  int y=query(d[i],x)-query(c[i].a-1,x)+1;
                  if (y==d[i]-c[i].a+2-tt) cout<<INF<<endl;
              else cout<<k_th(c[i].a,d[i],y+tt)<<endl;
                }
            }
    }

    4.分块

  • 相关阅读:
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    codevs 2977 二叉堆练习1x
    codevs 2010 求后序遍历x
    二叉树的序遍历x(内含结构体与非结构体版x)
    医院设置x
    求后序遍历x
    [LightOJ1017]Brush (III)(dp)
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/8419947.html
Copyright © 2020-2023  润新知