[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;
        }
    }
}

 

posted @ 2018-02-03 15:05  尹吴潇  阅读(112)  评论(0编辑  收藏  举报