2014.10.6模拟赛【魔兽争霸】

魔兽争霸(war.pas)

小x正在销魂地玩魔兽

他正控制着死亡骑士和n个食尸鬼(编号1~n)去打猎

 

死亡骑士有个魔法,叫做“死亡缠绕”,可以给食尸鬼补充HP

战斗过程中敌人会对食尸鬼实施攻击,食尸鬼的HP会减少

 

小x希望随时知道自己部队的情况,即HP值第k多的食尸鬼有多少HP,以便决定如何施放魔法

请同学们帮助他:)

 

小x向你发出3种信号:(下划线在输入数据中表现为空格)

A_i_a表示敌军向第i个食尸鬼发出了攻击,并使第i个食尸鬼损失了a点HP,如果它的HP<=0,那么这个食尸鬼就死了(Undead也是要死的……)。

敌军不会攻击一个已死的食尸鬼。

C_i_a 表示死亡骑士向第i个食尸鬼放出了死亡缠绕,并使其增加了a点HP。

HP值没有上限。

死亡骑士不会向一个已死的食尸鬼发出死亡缠绕

Q_k  表示小x向你发出询问

 

输入(war.in)

第一行,一个正整数 n

以后n个整数 表示n个食尸鬼的初始HP值

接着一个正整数m

以下m行 每行一个小x发出的信号

 

输出(war.out)

对于小x的每个询问,输出HP第k多的食尸鬼有多少HP,如果食尸鬼总数不足k个,输出-1。每个一行数。

最后一行输出一个数:战斗结束后剩余的食尸鬼数

 

样例

Input

Output

5

1 2 3

4 5

10

Q 2

A 4 6

C 1 4

Q 2

A 2 1

A 3 3

A 1 3

Q 4

C 2 10

Q 1

4

5

-1

11

3

 

 

约定

40%的数据 n<=3000  m<=5000

70%的数据  n<=8000  m<=10000

100%的数据 n<=30000  m<=50000

90%的数据随机生成

食尸鬼HP没有上限

数据保证任意时刻食尸鬼的HP值在longint范围内

数据保证A和C命令中的食尸鬼是活着的

输入数据中没有多余空格、换行


听说这是难度noip普及组的模拟赛啊……为毛有平衡树

支持三种操作:插入,删除,第k大。

还要保存一下原来编号i的食尸鬼在treap中的节点编号

唉考场上贴了模板结果后面处理的不对还是爆蛋

也就200行

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<ctime>
#define LL long long
#define inf 0x7ffffff
#define pa pair<int,int>
#define pi 3.1415926535897932384626433832795028841971
#define N 100010
using namespace std;
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct node{
    int l,r,num,rando,sons,rep;
}tree[N];
int treesize,root,n,m,ans,tot;
int from[N];
void update(int now)
{
    tree[now].sons = tree[tree[now].l].sons + tree[tree[now].r].sons + tree[now].rep;
}
void right_rotate(int &work)
{
    int t = tree[work].l;
    tree[work].l = tree[t].r;
    tree[t].r = work;
    tree[t].sons = tree[work].sons;
    update(work);
    work = t;
}
 
void left_rotate(int &work)
{
    int t = tree[work].r;
    tree[work].r = tree[t].l;
    tree[t].l = work;
    tree[t].sons = tree[work].sons;
    update(work);
    work = t;
}
 
int insert(int &now,int x)
{
     
    if (now == 0)
    {
        now = ++treesize;
        tree[now].rando = rand();
        tree[now].num = x;
        tree[now].rep=tree[now].sons = 1;
        return now;
    }
    tree[now].sons++;
    int save=now;
    if (tree[now].num==x) 
    {
        tree[now].rep++;
        return now;
    }
    if (x < tree[now].num)
    {
    	save=insert(tree[now].l,x);
        if (tree[tree[now].l].rando < tree[now].rando) right_rotate(now);
    }
    else
    {
        save=insert(tree[now].r,x);
        if (tree[tree[now].r].rando < tree[now].rando) left_rotate(now);
    }
    return save;
}
 
void del(int &now,int x)
{
    if (now == 0) return;
    if (tree[now].num==x)
    {
        if (tree[now].rep>1)
        {
            tree[now].rep--;
            tree[now].sons--;
            return;
        } 
        if (tree[now].l*tree[now].r==0)
          now=tree[now].l+tree[now].r;
        else
        if (tree[tree[now].l].rando<tree[tree[now].r].rando)
        {
            right_rotate(now);
            del(now,x);
        }
        else
        {
            left_rotate(now);
            del(now,x);
        }
    }
    else
    if (x>tree[now].num)
    {
        tree[now].sons--;
        del(tree[now].r,x);
    }
    else
    {
        tree[now].sons--;
        del(tree[now].l,x);
    }
}
int ask_rank(int now,int x)
{
    if (now==0) return 0;
    if (tree[now].num==x) return tree[tree[now].l].sons+1;
    else
    if (x>tree[now].num)
    return tree[tree[now].l].sons+tree[now].rep+ask_rank(tree[now].r,x);
    else
    return ask_rank(tree[now].l,x);
}
int ask_num(int now,int x)
{
	if (tree[now].sons<x)return -1;
    if(now==0)return 0;
    if(x<=tree[tree[now].l].sons)return ask_num(tree[now].l,x);
    else if(x>tree[tree[now].l].sons+tree[now].rep)return ask_num(tree[now].r,x-tree[tree[now].l].sons-tree[now].rep);
    else return tree[now].num;
}
void succ(int now,int x)
{
    if(now==0)return;
    if(tree[now].num<x){ans=tree[now].num;succ(tree[now].r,x);}
    else succ(tree[now].l,x);
}
void pred(int now,int x)
{
   if(now==0)return;
   if(tree[now].num>x){ans=tree[now].num;pred(tree[now].l,x);}
   else pred(tree[now].r,x);
}
int main()
{
	freopen("war.in","r",stdin);
	freopen("war.out","w",stdout);
	srand(time(0));
	n=read();tot=n;
	for (int i=1;i<=n;i++)
	  {
	  	int x=read();
	  	from[i]=insert(root,x);
	  }
	m=read();
	for (int i=1;i<=m;i++)
	{
	 	char ch=getchar();
	 	while (ch!='A'&&ch!='C'&&ch!='Q')ch=getchar();
	 	if (ch=='Q')
		 {
		 	int x=read();
		 	if (x>tot)printf("-1\n");
		    else cout<<ask_num(root,tot-x+1)<<endl;
		 }
	 	if (ch=='A')
	 	{
	 		int x=read(),y=read();
	 		int fx=from[x],d=tree[fx].num;
	 		printf("%d %d\n",d,y);
	 		del(root,d);
	 		if (d-y<=0)
	 		{
	 			from[x]=-1;
	 			tot--;
	 		}else
	 		{
	 			from[x]=insert(root,d-y);
	 		}
	 	}
	 	if (ch=='C')
	 	{
	 		int x=read(),y=read();
	 		int fx=from[x],d=tree[fx].num;
	 		del(root,d);
	 		from[x]=insert(root,d+y);
	 	}
	}
	printf("%d\n",tot);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值