KPI HDU - 5249【权值线段树】

KPI HDU - 5249【权值线段树】

Problem Description:

你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度。数十亿的请求被推到一个大管道后同时服务从管头拉取请求。让我们来定义每个请求都有一个重要值。我的KPI是由当前管道内请求的重要值的中间值来计算。现在给你服务记录,有时我想知道当前管道内请求的重要值得中间值。

Input:

有大约100组数据。
每组数据第一行有一个n(1≤n≤10000),代表服务记录数。
接下来有n行,每一行有3种形式
“in x”: 代表重要值为x(0≤x≤109)的请求被推进管道。
“out”: 代表服务拉取了管道头部的请求。
"query: 代表我想知道当前管道内请求重要值的中间值. 那就是说,如果当前管道内有m条请求, 我想知道,升序排序后第 f l o o r ( m / 2 ) + 1 t h floor(m/2)+1th floor(m/2)+1th条请求的重要值.
为了让题目简单,所有的x都不同,并且如果管道内没有值,就不会有"out"和"query"操作。

output:

对于每组数据,先输出一行
Case # i:
然后每一次"query",输出当前管道内重要值的中间值。

Input:

6
in 874
query
out
in 24622
in 12194
query

output:

Case #1:
874
24622

思路:

离线操作,离散化数据,找到原数组的数据在排序后的数组的下标,将下标放进树中,之后再进行寻找第k大数(k=中间值)

详细

  • 离线操作
  • 离散化
  • 第k大数
  1. 首先我们进行的应该是离线操作,因为题目给出的数据都是一次一次的给出,所以当我们要建树的时候就碰到了困难,所以我们先需要离线操作,例如题目中的,给出的六组操作,我们可以令 1 代表 in,2 代表 out,3 代表 query,每次将操作取出以后存到一个队列里,例如:
queue<int >q;
for(int i=1;i<=6;i++)
{
	char demand[10];
	scanf("%s%*c",demand);
	if(demand[0]=='i')
		q.push(1);
	else
		if(demand[0]=='o')
			q.push(2);
	else
		q.push(3);
}	
  1. 将我们的操作处理好之后,我们就可以得知被推进管道里有多少个数据,之后我们就可以进行建树,并且离散化这些数据。
  2. 开辟两个数组,f[N]存放原数据,b[N]存放排序后的数据,(其实也可以用队列来存放原数据),之后,定义两个指针,都是用在f[N]上,一个是指向将要删除的数据,一个是指向将要放在树里的数据。
//根据操作之后原数据
f[3]={874,24622,12194}
//排序之后的数据
b[3]={274,12194,24622}
//根据f[i]在b中所对应的下标,进行操作
//874----1  24622---3  12194---2
//根据值找下标  ->  lower_bound()

lower_bound()

按照操作,依次放到树里,即在树中就已经排好了顺序,我们就可以在树中找到中间值。

AC代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#define N 20100
#define ll long long

using namespace std;

ll n,f[N],k,b[N];
ll sum;
deque<ll> cmd,dq;
struct T
{
    ll l;
	ll r;
	ll tag;
	ll sum;
} tree[N*4];

void Pushup(ll nt)
{
    tree[nt].sum=tree[nt*2].sum+tree[nt*2+1].sum;
}
void Build_tree(ll l,ll r,ll nt)
{
    tree[nt].l = l;
    tree[nt].r = r;
    tree[nt].tag=0;
    if(l==r)
    {
        tree[nt].sum=0;
        return ;
    }
    else
    {
        ll mid = (l+r)/2;
        Build_tree(l,mid,2*nt);
        Build_tree(mid+1,r,2*nt+1);
    }
    Pushup(nt);
}

void Update(ll nt)
{
    tree[2*nt].sum+=(tree[2*nt].r-tree[2*nt].l+1)*tree[nt].tag;
    tree[2*nt+1].sum+=(tree[2*nt+1].r-tree[2*nt+1].l+1)*tree[nt].tag;
    tree[2*nt].tag+=tree[nt].tag;
    tree[2*nt+1].tag+=tree[nt].tag;
    tree[nt].tag=0;
}

void Query_tree(ll a,ll nt)
{
    if(tree[nt].l==tree[nt].r)
    {
        sum=b[tree[nt].l];
        return ;
    }
    if(tree[2*nt].sum>=a)
        Query_tree(a,2*nt);
    else
        Query_tree(a-tree[2*nt].sum,2*nt+1);
}

void Insert_tree(ll a,ll nt)
{
    if(tree[nt].l==tree[nt].r)
    {
        tree[nt].sum=1;
        return ;
    }
    ll mid=(tree[nt].l+tree[nt].r)/2;
    if(mid>=a)
        Insert_tree(a,2*nt);
    else
        Insert_tree(a,2*nt+1);
    Pushup(nt);
}

void Delete_tree(ll a,ll nt)
{
    if(tree[nt].l==tree[nt].r)
    {
        tree[nt].sum=0;
        return ;
    }
    ll mid=(tree[nt].l+tree[nt].r)/2;
    if(mid>=a)
        Delete_tree(a,2*nt);
    else
        Delete_tree(a,2*nt+1);
    Pushup(nt);
}
int main()
{
    ll t,x=1;
    while(~scanf("%lld%*c",&t))  //离线操作
    {
        ll point1=0,point=0,cnt=0;
        memset(f,0,sizeof(f));
        memset(b,0,sizeof(f));
        memset(tree,0,sizeof(tree));
        printf("Case #%lld:\n",x++);
        for(int i=1;i<=t;i++)
        {
            char demand[10];
            scanf("%s%*c",demand);
            if(demand[0]=='i')
            {
                cnt++;
                scanf("%lld%*c",&f[cnt]);
                b[cnt]=f[cnt];
                cmd.push_back(1);

            }
            else
                if(demand[0]=='o')
                    cmd.push_back(2);
            else
                if(demand[0]=='q')
                    cmd.push_back(3);
        }
        ll len=cnt;
        Build_tree(1,cnt,1);
        sort(b+1,b+len+1);
        cnt=0;
        for(int i=1;i<=t;i++)
        {
            ll oper=cmd.front();
            cmd.pop_front();
            if(oper==1)//     Next : in
            {
                    point1++; //在原数组中即将放到树中的下标
                    cnt++;
                    ll data=lower_bound(b+1,b+len+1,f[point1])-b;
                    Insert_tree(data,1);
            }
            else
                if(oper==2) //删除操作
                {
                    point++;//模拟队列首
                    cnt--;
                    ll delete_sub=lower_bound(b+1,b+len+1,f[point])-b;
                    Delete_tree(delete_sub,1);
                }
            else
                if(oper==3)  //查找操作
                {
                    Query_tree(cnt/2+1,1);
                    printf("%lld\n",sum);
                }
        }
    }
    return 0;
}

Tips:

这里我都用的long long,其中一些变量用int就好,每次操作全部完成之后,不要忘记数组清零(WA了三遍 ),代码写的不好,勿喷

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值