现在的位置: 首页 > 综合 > 正文

魔兽争霸

2013年10月03日 ⁄ 综合 ⁄ 共 3435字 ⁄ 字号 评论关闭

魔兽争霸(war.pas/cpp/c)

    小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                     4

     1 2 3               5

     4 5                -1

     10                 11

     Q 2                 3

     A 4 6

     C 1 4

     Q 2

     A 2 1

     A 3 3

     A 1 3

     Q 4

     C 2 10

     Q 1

 

约定

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

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

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

   90%的数据随机生成。

   食尸鬼HP 没有上限。

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

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

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

评测数据下载:http://pan.baidu.com/share/link?shareid=432194&uk=255096381&third=15

解法:sbt。

可以用sbt解决此题,以root为根,s[i] 记录以 i 为根的树的节点数,l[i] 记录 i 号点的左儿子,y[i] 记录 i 号点的右儿子,p[i] 记录 i 号点的值。

对于A操作,①找到 a 点在树中的位置,②将a点删除,p[a]-=b,若p[a]>0--->insert(root,a);

对于C操作,①找到 a 点在树中的位置,②将a点删除,p[a]+=b,insert(root,a);

对于Q操作,若a>a[root]--->printf("-1\n"),否则select(root,a);

对于A、C操作,①操作用find(int  t,int k)找到k号点在树中的位置,②操作,先用get(int  t,int k)找到p[k]在树中的后继节点,然后用p[k]的后继结点代替k号节点。

代码:

#include<cstdio>
#include<algorithm>
#define maxn (30000+100)
using namespace std;

int root=0,s[maxn],l[maxn],r[maxn],p[maxn];

void init()
{
  freopen("war.in","r",stdin);
  freopen("war.out","w",stdout);
}

inline void data(int &t,int k)
{
  s[k]=s[t];
  s[t]=s[l[t]]+s[r[t]]+1;
  t=k;
}

inline void right_rotate(int &t)
{
  int k;
  k=l[t],l[t]=r[k],r[k]=t;
  data(t,k);
}

inline void left_rotate(int &t)
{
  int k;
  k=r[t],r[t]=l[k],l[k]=t;
  data(t,k);
}

void maintain(int &t,bool flag)
{
  if(flag)
    if(s[l[l[t]]]>s[r[t]])
      right_rotate(t);
    else
      if(s[r[l[t]]]>s[r[t]])
        left_rotate(l[t]),right_rotate(t);
      else 
        return;
  else
    if(s[r[r[t]]]>s[l[t]])
      left_rotate(t);
    else
      if(s[l[r[t]]]>s[l[t]])
        right_rotate(r[t]),left_rotate(t);
      else
        return;
  maintain(l[t],1);
  maintain(r[t],0);
  maintain(t,1);
  maintain(t,0);                   
}

void insert(int &t,int k)
{
  if(t==0)
    {
      t=k,l[t]=r[t]=0,s[t]=1;
      return;
    }
  s[t]++;
  if(p[k]<p[t])insert(l[t],k);
  else insert(r[t],k);
  maintain(t,p[k]<p[t]);  
}

void get(int &t,int &k)
{
  s[t]--;
  if(s[l[t]]==0)//找到后继节点 
    {
      int kk=r[t];
      l[t]=l[k],s[t]=s[k];
      r[t]=r[k]==t?r[t]:r[k];//处理t是k的儿子/非儿子的情况
      s[k]=0,k=t,t=kk;      
      return;
    }
  get(l[t],k);  
}
//在以t为根的树中,找到k号点,若能找到,则返回1,否则返回0 
//若p[t]==p[k],那么k号点可能在l[t]中,也可能在r[t]中,所以把find()定义为bool
//若p[k]<p[t],k一定在l[t]中;
//若p[k]>p[t],k一定在r[t]中 
//若p[k]==p[t],若find(l[t],k)==1,则k在l[t]中,若find(r[t],k)==1,则k在r[t]中 
bool find(int &t,int k) 
{
  s[t]--;
  if(t==k)//t==k,t号点已找到 
    {
      if(s[r[t]]==0 || s[l[t]]==0)s[t]=0,t=l[t]+r[t];
      else get(r[t],t);
      return 1;
    }  
  bool ok=0;
  if(p[k]<=p[t] && s[l[t]]>0)ok=find(l[t],k);
  if(ok)return 1;
  if(p[k]>=p[t] && s[r[t]]>0)ok=find(r[t],k);
  if(ok)return 1;
  s[t]++;//k不在t这颗树中,s[t]--就多减了,这里把它加回去 
  return 0;
}

void select(int t,int k)
{
  if(s[r[t]]+1==k){printf("%d\n",p[t]);return;}
  if(k<=s[r[t]])select(r[t],k);
  else select(l[t],k-s[r[t]]-1);
}
void work()
{
  int n,m,i,a,b; 
  s[0]=l[0]=r[0]=p[0]=0;
  scanf("%d",&n);
  for(i=1;i<=n;i++)
    scanf("%d",&p[i]),insert(root,i);
  
  char ss[10];
  scanf("%d",&m);
  for(i=1;i<=m && scanf("%s",ss)!=EOF;i++)
    switch (ss[0])
      {
        case 'A':scanf("%d%d",&a,&b);
                 find(root,a),p[a]-=b;
                 if(p[a]>0)insert(root,a);
                 break;
        case 'C':scanf("%d%d",&a,&b);
                 find(root,a),p[a]+=b;
                 insert(root,a);  
                 break;
         default:scanf("%d",&a);
                 if(a>s[root])printf("-1\n");
                 else select(root,a);
                 break;                 
      }  
  printf("%d\n",s[root]);
}

int main()
{
  init();
  work();
  return 0;
}

抱歉!评论已关闭.