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...也可能是我太渣了...毕竟伸展树有更加高能的作用...)


  • 相关阅读:
    概率图模型导论
    超平面与法向量
    感知机
    最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等
    数组去重的几种方法
    Vuex学习笔记(-)安装vuex
    js判断一个字符串是否是回文字符串
    取出字符串中的所有数字
    js将手机号中间四位变成*号
    微信小程序电商实战(-)商城首页
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793924.html
Copyright © 2011-2022 走看看