zoukankan      html  css  js  c++  java
  • 【NOI2004T1】郁闷的出纳员-平衡树入门题

    题目:郁闷的出纳员

    做法:了解平衡树这个数据结构的人应该一眼就能看出这个题目可以用平衡树做(平衡树的教程网上太多了,这里就不赘述了),用平衡树维护插入、删除、查找第k小(注意由于题目中询问第k大,就是查找第(目前员工数-k+1)小)的操作即可,再用一个数delta来记录工资的整体变化量,注意处理就可以了。

    以下是本人代码:

    Treap 树堆(2016.8.10):

    #include <cstdio>
    #include <cstdlib>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int m,n,k,delta=0,root=0,cnt=0,ans=0;
    char op;
    struct node
    {
      int son[2],size,pri,key;
      void newnode()
      {
        son[0]=son[1]=0;
    	size=1;pri=rand();
      }
    }tree[100010];
    
    void rotate(int &v,bool p)
    {
      int x=tree[v].son[!p];
      tree[v].son[!p]=tree[x].son[p];
      tree[x].son[p]=v;
      tree[x].size=tree[v].size;
      tree[v].size=tree[tree[v].son[0]].size+tree[tree[v].son[1]].size+1;
      v=x;
    }
    
    void insert(int &v,int key)
    {
      if (v==0)
      {
        v=++cnt;
        tree[v].key=key;
    	tree[v].newnode();
      }
      else
      {
        tree[v].size++;
    	bool p=key<tree[v].key;
    	insert(tree[v].son[!p],key);
    	if (tree[v].pri<tree[tree[v].son[!p]].pri) rotate(v,p);
      }
    }
    
    int del(int &v,int key)
    {
      int t;
      if (v==0) return 0;
      if (tree[v].key<key)
      {
        t=tree[tree[v].son[0]].size+1;
    	v=tree[v].son[1];
    	return t+del(v,key);
      }
      else
      {
        t=del(tree[v].son[0],key);
    	tree[v].size-=t;
    	return t;
      }
    }
    
    int get_Kth(int &v,int k)
    {
      int s=tree[tree[v].son[0]].size+1;
      if (k<s) return get_Kth(tree[v].son[0],k);
      if (k>s) return get_Kth(tree[v].son[1],k-s);
      return tree[v].key;
    }
    
    int main()
    {
      srand(time(NULL));
      scanf("%d%d",&n,&m);getchar();
      while(n--)
      {
        scanf("%c%d",&op,&k);getchar();
    	if (op=='I')
    	{
    	  if (k>=m) insert(root,k-delta);
    	}
    	if (op=='A') delta+=k;
    	if (op=='S')
    	{
    	  delta-=k;
    	  ans+=del(root,m-delta);
    	}
    	if (op=='F')
    	{
    	  if (!root||k>tree[root].size) printf("-1
    ");
    	  else printf("%d
    ",get_Kth(root,tree[root].size-k+1)+delta);
    	}
      }
      printf("%d
    ",ans);
      
      return 0;
    }
    
    Splay Tree 伸展树(2016.8.26):

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,m,root=0,top=0,delta=0,ans=0;
    int ch[100010][2],pre[100010],siz[100010],val[100010],c[100010],k;
    char op[20];
    
    void up(int x)
    {
      siz[x]=c[x]+siz[ch[x][0]]+siz[ch[x][1]];
    }
    
    void rotate(int x,int f)
    {
      int y=pre[x];
      ch[y][!f]=ch[x][f];
      pre[ch[x][f]]=y;
      pre[x]=pre[y];
      if (pre[x]) ch[pre[y]][ch[pre[y]][1]==y]=x;
      ch[x][f]=y;
      pre[y]=x;
      up(y);
    }
    
    void Splay(int x,int goal)
    {
      while(pre[x]!=goal)
      {
        if (pre[pre[x]]==goal) rotate(x,ch[pre[x]][0]==x);
    	else
    	{
    	  int y=pre[x],z=pre[y];
    	  int f=(ch[z][0]==y);
    	  if (ch[y][f]==x) rotate(x,!f),rotate(x,f);
    	  else rotate(y,f),rotate(x,f);
    	}
      }
      up(x);
      if (goal==0) root=x;
    }
    
    void newnode(int &v,int key,int f)
    {
      v=++top;
      val[v]=key;pre[v]=f;
      ch[v][0]=ch[v][1]=0;
      siz[v]=c[v]=1;
    }
    
    void insert(int &v,int key,int f)
    {
      if (!v)
      {
        newnode(v,key,f);
    	Splay(v,0);
    	return;
      }
      if (key==val[v])
      {
        c[v]++;siz[v]++;
    	Splay(v,0);
    	return;
      }
      insert(ch[v][key>val[v]],key,v);
      up(v);
    }
    
    int get_Kth(int x,int k)
    {
      int s=siz[ch[x][0]]+c[x];
      if (k<=s-c[x]) return get_Kth(ch[x][0],k);
      else if (k>s) return get_Kth(ch[x][1],k-s);
           else
    	   {
    	     Splay(x,0);
    		 return val[x];
    	   }
    }
    
    int getkey(int x,int key)
    {
      if (key<val[x]) return getkey(ch[x][0],key);
      else if (key>val[x]) return getkey(ch[x][1],key);
           else
    	   {
    	     Splay(x,0);
    		 return x;
    	   }
    }
    
    void rto(int k,int goal)
    {
      int x=root;
      while(1)
      {
        if (k<=siz[ch[x][0]]) x=ch[x][0];
    	else if (k>siz[ch[x][0]]+c[x]) {k-=siz[ch[x][0]]+c[x];x=ch[x][1];}
    	     else break;
      }
      Splay(x,goal);
    }
    
    void del_root()
    {
      int t=root;
      if (ch[root][1])
      {
        root=ch[root][1];
    	rto(1,0);
    	ch[root][0]=ch[t][0];
    	if (ch[t][0]) pre[ch[t][0]]=root;
      }
      else root=ch[root][0];
      pre[root]=0;
      up(root);
    }
    
    void Delete(int key)
    {
      int node=getkey(root,key);
      Splay(node,0);
      c[root]--;
      if (!c[root]) del_root();
    }
    
    int main()
    {
      scanf("%d%d",&n,&m);
      ch[0][0]=ch[0][1]=pre[0]=siz[0]=c[0]=val[0]=0;
      
      while(n--)
      {
        scanf("%s%d",op,&k);
    	if (op[0]=='I') {if (k>=m) insert(root,k-delta,0);}
    	if (op[0]=='A') delta+=k;
    	if (op[0]=='S')
    	{
    	  delta-=k;
    	  int Min;
    	  while(siz[root]&&(Min=get_Kth(root,1))<m-delta)
    	  {
    	    Delete(Min);
    	    ans++;
    	  }
    	}
    	if (op[0]=='F')
    	{
    	  if (siz[root]<k) printf("-1
    ");
    	  else printf("%d
    ",get_Kth(root,siz[root]-k+1)+delta);
    	}
      }
      printf("%d",ans);
      
      return 0;
    }
    
    (个人感觉这题用伸展树编程复杂度较高而且不如treap...也可能是我太渣了...毕竟伸展树有更加高能的作用...)


  • 相关阅读:
    修改器 $set 设置某个键的值 ,修改器 $unset 删除某个键
    修改器 $inc 增加和减少
    IIS 7.5 Express配置文件解析
    MongoDB 安装
    GUID 字符串,16位字符串,19位数字
    MongoDB Shell 学习
    数组修改器 $push $ne ($addToSet $each ) $pop $pull
    但行好事,莫问前程!
    gitlab使用过程中的需求与解决
    [其它] 为什么中国的程序员技术偏低
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793924.html
Copyright © 2011-2022 走看看