[平衡树]牛耳杯程序设计大赛决赛D题——BallIntheBox

原创 2012年03月27日 11:55:44

题目描述:

Balls In The Box

Time limit: 1s    Memory limit: 32768 kb

Problem Description

There are N boxes in Staginner’s house, and we mark them by 1,2,…,N. There are Ni(1<=Ni<=10^4) balls in the box i initially. Now Staginner will do some operations, and he will ask you some simple questions.

The operations contain:

1. C i j : take all the balls in the box i into the box j and throw the box i away, you can sure that i is different from j.

2. A i n : add n(1<=n<=10^4) balls into the box i.

    3. B i n : take n(n>=0) balls away from box i, you can sure that n is not bigger than the number of balls in the box i.

    4. Q k : Staginner ask you for the k-th smallest number of balls in the box, you can sure that k is not bigger than the total number of boxes.

Input:

There are several test cases.

The first line of each case contains two integers, N(1<=N<=10^5), M(1<=M<=10^5), indicates the number of boxes and the number of operations. The next line contains N integers, the i-th integer indicates the number of balls in the box i. Then there will be M lines, each line has an operation like someone of the operations in the description.

Output:

For each test case, you need only print one integer for each operation “Q k”, indicates the k-th smallest number of balls in the box.

Sample Input:

3 7

1 2 3

A 3 1

C 2 1

Q 1

B 3 4

Q 1

C 3 1

Q 1

Sample Output:

3

0

3

 

题目意思很简单,给定N个盒子和M个操作,然后给出初始时每个盒子里球的个数,接下来时M个操作,操作分为四种,

A a b :把编号为a的盒子里的球的数量增加b

B a b :把编号为a的盒子里的球的数量减少b

C a b :把编号为a的盒子里的球全倒进编号为b的盒子里,然后扔掉盒子a

Q k :查询球数第k小的盒子,对于每一个Q输出一行为该盒子里的球数

思路,如果用数组直接存,A B C 三个操作都容易实现,复杂度为O(1),然而Q操作每次都会花费O(n)的时间,n达到10^5,而且有10^5个询问,给定时限只有1s,肯定超时,于是想到用平衡二叉树来动态维护这些盒子,这样A B C D的时间复杂度都为O(logn),应该不会超时。

郁结的过程:比赛当时由于SBT不会写。。AVL写的不熟,然后果断放弃了该题,比赛之后弄到了题目和数据,自己在本地慢慢的搞,起初只用盒子里的球数来作为关键码,这样对于球数相同的情况是不能够处理了(经过旋转会破坏BST的性质),然后想到用盒子的球数和盒子的编号一起做关键码(球数为第一关键码,编号为第二关键码),这样就能够保证所有的关键码都不相同,于是终于AC了。 总算是把AVL写的比较熟练了。虽然代码风格比较挫。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100010;
//关键码结点类 
struct Node
{
   int wgt;
   int num;
   Node(int w=0,int n=0):wgt(w),num(n){}
   bool operator < (const Node &n) const
   {
        if(wgt!=n.wgt)return wgt<n.wgt;
        else return num<n.num;
   }   
   bool operator == (const Node &n) const
   {
        return wgt==n.wgt&&num==n.num;
   }
};
//AVL树 
struct AVLTree
{
   int l[MAXN],r[MAXN],size[MAXN],next[MAXN],h[MAXN],ROOT;
   Node Key[MAXN];
   int newnode(int w,int n)
   {
        int node = next[0];
        Key[node].wgt = w;
        Key[node].num = n;
        next[0] = next[node];
        h[node] = size[node] = 1;
        return node;
   }
   void delnode(int x)
   {
        next[x] = next[0];
        next[0] = x;
        Key[x].wgt = Key[x].num = h[x] = size[x] = l[x] = r[x] = 0;
   }
   void init()
   {
       for(int i=0;i<MAXN;i++)next[i]=i+1;
       memset(l,0,sizeof(l));
       memset(r,0,sizeof(r));
       memset(size,0,sizeof(size));
       memset(h,0,sizeof(h));
       ROOT = 0;
   }    
   void left_rotate(int &p)
   {
       int x = r[p];
       r[p] = l[x];
       l[x] = p;
       size[p] = size[l[p]]+size[r[p]]+1;
       size[x] = size[l[x]]+size[r[x]]+1;
       h[p] = max(h[l[p]],h[r[p]])+1;
       h[x] = max(h[l[x]],h[r[x]])+1;
       p = x;
   }
   void right_rotate(int &p)
   {
       int x = l[p];
       l[p] = r[x];
       r[x] = p;
       size[p] = size[l[p]]+size[r[p]]+1;
       size[x] = size[l[x]]+size[r[x]]+1;
       h[p] = max(h[l[p]],h[r[p]])+1;
       h[x] = max(h[l[x]],h[r[x]])+1;
       p = x;
   }
   void insert(int &p,Node k)
   {
        if(!p)
        {
              
            p = newnode(k.wgt,k.num);
            return;
        }
        if(k<Key[p])insert(l[p],k);
        else insert(r[p],k);
        h[p] = max(h[l[p]],h[r[p]])+1;
        size[p] = size[l[p]]+size[r[p]]+1;
        if(h[l[p]]-h[r[p]]==2)//L
        {
            if(h[l[l[p]]]>h[r[l[p]]])//LL
            {
                right_rotate(p);
            }
            else 
            {
                left_rotate(l[p]);
                right_rotate(p);
            }
        }
        else if(h[l[p]]-h[r[p]]==-2)//R
        {
            if(h[r[r[p]]]>h[l[r[p]]])//RR
            {
                left_rotate(p);
            }
            else 
            {
                right_rotate(r[p]);
                left_rotate(p);
            }
        }
   }
   int findmin(int &p)
   {
       if(l[p])return findmin(l[p]);
       return p;
   }
   void remove(int &p,Node k)
   {
       if(p)
       {
           if(k==Key[p])
           {
               if(!l[p])
               {
                   int x = p;
                   p = r[p];
                   delnode(x);
               }
               else if(!r[p])
               {
                   int x = p;
                   p = l[p];
                   delnode(x);
               }
               else
               {
                   int x = findmin(r[p]);
                   Key[p] = Key[x];
                   remove(r[p],Key[x]);
               }
           }
           else if(k<Key[p])remove(l[p],k);
           else remove(r[p],k);
           if(p)
           {
               h[p] = max(h[l[p]],h[r[p]])+1;
               size[p] = size[l[p]]+size[r[p]]+1;
           }
            if(h[l[p]]-h[r[p]]==2)//L
            {
                if(h[l[l[p]]]>h[r[l[p]]])//LL
                {
                    right_rotate(p);
                }
                else 
                {
                    left_rotate(l[p]);
                    right_rotate(p);
                }
            }
            else if(h[l[p]]-h[r[p]]==-2)//R
            {
                if(h[r[r[p]]]>h[l[r[p]]])//RR
                {
                    left_rotate(p);
                }
                else 
                {
                    right_rotate(r[p]);
                    left_rotate(p);
                }
            }
       } 
   }
   int Select(int p,int k)
   {
       int rank = size[l[p]]+1;
       if(rank==k)return p;
       else if(rank<k) return Select(r[p],k-rank);
       return Select(l[p],k);
   }
}avl;
int a[MAXN];
int main()
{
    int n,m;
    freopen("D.in","r",stdin);
    freopen("DansK2.out","w",stdout);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        avl.init();
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)avl.insert(avl.ROOT,Node(a[i],i));
        for(int i=0;i<m;i++)
        {
            char op[5];int x,y;
            scanf("%s",op);
            if(op[0]=='A')
            {
                scanf("%d%d",&x,&y);
                avl.remove(avl.ROOT,Node(a[x],x));
                a[x]+=y;
                avl.insert(avl.ROOT,Node(a[x],x));
            }
            else if(op[0]=='B')
            {
                scanf("%d%d",&x,&y);
                avl.remove(avl.ROOT,Node(a[x],x));
                a[x]-=y;
                avl.insert(avl.ROOT,Node(a[x],x));
            }
            else if(op[0]=='C')
            {
                scanf("%d%d",&x,&y);
                avl.remove(avl.ROOT,Node(a[x],x));
                avl.remove(avl.ROOT,Node(a[y],y));
                a[y]+=a[x];
                avl.insert(avl.ROOT,Node(a[y],y));
            }
            else
            {
                scanf("%d",&x);
                printf("%d\n",avl.Key[avl.Select(avl.ROOT,x)].wgt);
            }
        }
    }
    return 0;
}


 

2017第七届吉首大学“新星杯”程序设计大赛(暨新生网络同步赛)

A #include #include #include #include #include #include #include #include #include #includ...
  • sasuke__
  • sasuke__
  • 2017年12月26日 20:23
  • 174

第十五届“华为杯”大学生程序设计竞赛题解

1.虢莔薅参加运动会 解法:1^2+2^2+3^2+...n^2=n*(n+1)*(2*n+1)/6代入求解,注意6的逆元求法 题目类型:数论裸题 #include #define ll lo...
  • w1y2s312138
  • w1y2s312138
  • 2017年04月20日 23:44
  • 769

牛耳杯程序设计大赛总结

虽然是个小小的比赛,还是写一个总结吧。   不知不觉患上了疑似神经衰弱的病,头已经晕了4天了,状态也不怎么好,勉强能够做题。 也算是这次比赛悲剧的一个小小的因素吧。 下面回顾整场比赛悲剧的过程:...
  • Airarts_
  • Airarts_
  • 2012年03月25日 23:50
  • 1236

〖2016〗吉首大学第六届新星杯暨程序设计大赛(新生网络同步赛)-题解

A 题目描述 C语言函数,数学函数,傻傻分不清楚~~ 题目很简单,我们定义F(x)是满足x取余a乘b的积等于0(即:x%(a*b)==0)这样的a,b的组数。现在给你一个n,你需要求出 F(n)。...
  • Fantastic_
  • Fantastic_
  • 2016年12月25日 04:12
  • 924

2017湖南大学ACM程序设计新生杯大赛 - B - Build (并查集&&贪心)

#include #include #include #include using namespace std; const int N = 1e6 + 10; int n,m,q,k; in...
  • w326159487
  • w326159487
  • 2018年01月21日 22:36
  • 29

湖南大学ACM程序设计新生杯大赛(同步赛)A-Array 【证明+暴力】

时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言262144K 64bit IO Format: %lld 题目描述 Given an array A ...
  • Irish_Moonshine
  • Irish_Moonshine
  • 2017年12月24日 18:31
  • 71

2017年“华信智原杯”安徽省大学生程序设计大赛C题刷票

2017年“华信智原杯”安徽省大学生程序设计大赛 C题刷票 题目描述:        有一个选秀比赛,节目组按照观众的投票情况决定选手的去留。为了给旗下的艺人造势,A公司收买了一批水军来刷票。...
  • qq_37135801
  • qq_37135801
  • 2017年09月26日 12:22
  • 168

湖南大学ACM程序设计新生杯大赛(同步赛)

C Do you like Banana ? https://www.nowcoder.com/acm/contest/55/C 分析:判断两条线段是否相交D Number https:...
  • feng_zhiyu
  • feng_zhiyu
  • 2017年12月24日 18:48
  • 138

赛博地球杯工业互联网安全大赛-大量设备报表不见了(签道题)

自己也是前几天刚入ctf的小白,比赛前两天就被拉着参赛。不得不说个人觉得这个比赛挺难的。下面看看这个签到题怎么做吧~ 题目:云平台报表中心收集了设备管理基础服务的数据,但是数据被删除了,只有一处留下了...
  • qq_32448559
  • qq_32448559
  • 2018年01月23日 16:00
  • 72

2017安徽程序设计竞赛总结

准备了好多,比赛终于在上个周末结束了。 昨天知道了结果,一个说不上好,却也还能勉强接受的结果(感谢两位姓王的大腿,哈哈)。 二等倒五吧。 自己开始准备的很多东西都没有用的上,想想原因或许很多。 1.自...
  • liuzhenghui666666
  • liuzhenghui666666
  • 2017年05月24日 23:46
  • 438
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[平衡树]牛耳杯程序设计大赛决赛D题——BallIntheBox
举报原因:
原因补充:

(最多只允许输入30个字)