• [ZJOI2007]报表统计


    链接:https://www.luogu.org/problemnew/show/P1110

    题解:

    一道不错的模板题

    对于第一个询问,只需维护一个支持删除的堆

    方法1.再维护一个堆,将删除的数加入这个堆,每次取元素时判断一下是否和另一个堆相等

    方法2.利用左偏树可以删除任意节点(太久不写都忘了)

    当然也可以维护一颗平衡树

    对于第二个询问,只需弄一颗平衡树求它的前驱后继就可以了

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define INF 2000000000
    const int maxn=510000;
    int ans,num,a[maxn*2],n,m,pre[maxn*2],root,v[maxn*2],dis[maxn*2],
    left1[maxn*2],right1[maxn*2],fa[maxn*2],now,last[maxn*2],root2, 
    fa1[maxn*2],leftson[maxn*2],rightson[maxn*2],count2[maxn*2],data[maxn*2];
    char c[10];
    int merge(int r1,int r2)
    {
        if (r1==0||r2==0) return(r1+r2);
        if (v[r1]>v[r2]) swap(r1,r2);
        right1[r1]=merge(right1[r1],r2);
        fa1[right1[r1]]=r1;
        if (dis[left1[r1]]<dis[right1[r1]]) swap(left1[r1],right1[r1]);
        dis[r1]=dis[right1[r1]]+1;
        return(r1);
    }
    void delete1(int x)
    {
        if (x==0) return;
        int p=merge(left1[x],right1[x]),q=fa1[x];
        fa1[p]=q;
        if (x==root2) root2=p;
        if (q)
        {
            if (left1[q]==x) left1[q]=p;
            else right1[q]=p;
        }
        while (q)
        {
            if (dis[left1[q]]<dis[right1[q]]) swap(left1[q],right1[q]);
            if (dis[right1[q]]+1==dis[q]) return ;
        dis[q]=dis[right1[q]]+1; q=fa1[q];
        }
    }
    void updata(int x)
    {
        count2[x]=count2[leftson[x]]+count2[rightson[x]];
    }
    void rotate(int x,int y)
    {
        int father=fa[x];
     //   down(father); down(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)
    {
        if (x==root) 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=x;
    }
    void insert2(int x)
    {
        int y=root;
        while (y)
        {
            count2[y]++;
            if (x<data[y])
            {
                if (!leftson[y]) break;
                y=leftson[y];
            } else
            {
                if (!rightson[y]) break;
                y=rightson[y];
            }
        }
        data[++num]=x; fa[num]=y; count2[num]=1;
        if (x>data[y]) rightson[y]=num;
        else leftson[y]=num;
        splay(num,0);
    }
    void getans(int x)
    {
      int y=root,maxn=-INF;
      while (y)
      {
          if (data[y]<=x) maxn=max(maxn,data[y]);
          if (data[y]<=x) y=rightson[y];
          else y=leftson[y];
        }
        ans=min(ans,abs(maxn-x));
      y=root;int minn=INF;
        while (y)
        {
            if (data[y]>=x) minn=min(minn,data[y]);
            if (data[y]>=x) y=leftson[y];
            else y=rightson[y];
        }
        ans=min(ans,abs(minn-x));
    }
    int main()
    {
        freopen("noip.in","r",stdin);
        freopen("noip.out","w",stdout);
        cin>>n>>m; ans=INF;
        for (int i=1;i<=n;i++) cin>>a[i];
        for (int i=1;i<=n;i++) 
          getans(a[i]),
            insert2(a[i]); 
        for (int i=1;i<n;i++)
        {
            v[++now]=abs(a[i+1]-a[i]);
            root2=merge(root2,now);
            last[i]=now; pre[i]=a[i];
        }
        pre[n]=a[n];
        for (int i=1;i<=m;i++)
        {
            int d,e,f;
            cin>>c;
            if (c[4]=='R')
            {
                 cin>>d>>e;
                 delete1(last[d]);
                 v[++now]=abs(pre[d]-e);
                 root2=merge(root2,now);
                 v[++now]=abs(a[d+1]-e);
                 root2=merge(root2,now);
                 last[d]=now; pre[d]=e;
                 getans(e); insert2(e);
            }
            if (c[4]=='S') 
            {
                cout<<ans<<endl;
            }
            if (c[4]=='G')
            {
                cout<<v[root2]<<endl;
            }
        }
    }
  • 相关阅读:
    聊一聊HTML <pre>标签
    [Effective JavaScript 笔记]第20条:使用call方法自定义接收者来调用方法
    数据库的权限管理
    完整性约束
    MYSQL
    Python并发编程之协程
    python并发编程之多线程
    python并发编程之多进程
    进程
    网络编程之socket的运用
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/8409515.html
Copyright © 2020-2023  润新知