牛客网 wyh的天鹅 (权值线段树)

链接:https://www.nowcoder.com/acm/contest/93/L
来源:牛客网

你们wyh学长小时候住在河边,因为周围的生态环境非常好,所以经常会有天鹅浮在湖面上,每只天鹅都长得不一样,它们偶尔排成一排,偶尔分散开,偶尔也会去其他河畔,wyh学长为了统计它们的个数,编了一个程序赋予它们一个“萌”值,但是这些天鹅很不听话,一会儿会从别的地方游过来一两只,一会儿又会在统计过程中游走一两只,现在请你帮他完成统计任务。 
输入描述:
共有T(T<=10)组数据,每组数据第一行为两个数 N, M (N,M <= 500000),代表有N只天鹅和M次操作,接下来一行是N个数字,下面M行首先会输入一个字符串S,接着会有三类操作,如果S是“insert”,接着输入一个正整数a,代表插入一只“萌”值为a的天鹅,如果S是“delete”,接着输入一个正整数a,代表删除一只“萌”值为a的天鹅,如果S是“query”,接着输入一个正整数k,代表查询“萌”值第k大的天鹅。萌值为[1,1000000000],并且保证一定存在第k大
输出描述:
对应每次询问,输出询问结果。

示例1

输入

1
5 4
6 4 2 9 1
query 2
insert 7
delete 6
query 2

输出

6
7

分析:题中的三种操作分别是插入和删除一个固定的数,和询问第几大的数,可以用权值线段树或者平衡树

如果用权值线段树的话,因为数的范围很大,所以需要先将题目中出现的所有的数放入一个集合中来进行离散化处理

代码如下:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <map>
using namespace std;
const int N=5e5+100;
int T[N<<2];
int maxx;
int rec[N];
int a[N];
int t,n,m,x;
int cnt;

struct node
{
  char a[10];
  int x;
}qes[N];

void BuildTree(int rt,int l,int r)
{
  T[rt]=0;
  if(l==r)return;
  int mid=(l+r)>>1;
  BuildTree(rt<<1,l,mid);
  BuildTree(rt<<1|1,mid+1,r);
}

void Updata(int p,int v,int rt,int l,int r)  //插入v个值为p的数,若v为负数,即为删去.
{
  T[rt]+=v;
  if(l==r)return;
  int mid=(l+r)>>1;
  if(p<=mid)Updata(p,v,rt<<1,l,mid);
  else Updata(p,v,rt<<1|1,mid+1,r);
}

int kth(int k,int rt,int l,int r) //找到第k大的数
{
   if(l==r)return l;
   int mid=(l+r)>>1;
   if(T[rt<<1|1]>=k)return kth(k,rt<<1|1,mid+1,r);
   return kth(k-T[rt<<1|1],rt<<1,l,mid);
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        cnt=1;
        vector<int>V;  //将所有出现过的数放入V中,并且去重,方便离散处理
        map<int,int>mp;  //用来进行离散化处理
       memset(rec,0,sizeof(rec));//用来关联,离散化后的数和以前的数。

       scanf("%d%d",&n,&m);
       for(int i=1;i<=n;i++)
       {
           scanf("%d",&a[i]);
           V.push_back(a[i]);
       }

       for(int i=1;i<=m;i++)
       {
           scanf("%s%d",qes[i].a,&qes[i].x);
           V.push_back(qes[i].x);
       }
        sort(V.begin(),V.end());
       V.erase(unique(V.begin(),V.end()),V.end()); //去重操作

       for(int i=0;i<V.size();i++)
        {
             x=V[i];
             rec[cnt]=x;  //记录离散前的数
             mp[x]=cnt++;  //离散化
        }
        BuildTree(1,1,cnt);
       for(int i=1;i<=n;i++)
        Updata(mp[a[i]],1,1,1,cnt);

       for(int i=1;i<=m;i++)
       {
          if(qes[i].a[0]=='i')
          Updata(mp[qes[i].x],1,1,1,cnt);
          else if(qes[i].a[0]=='d')
          Updata(mp[qes[i].x],-1,1,1,cnt);
          else
          printf("%d\n",rec[kth(qes[i].x,1,1,cnt)]);
       }
    }
    return 0;
}

 

猜你喜欢

转载自www.cnblogs.com/a249189046/p/8858466.html