Gym102091 K.The Stream of Corning 2(离散+划分树?)

Little Oregon loves to play in the forest, but tonight he got lost on his way back home. While
trying to find his trail, he found a stream. No no, it was not a stream of hot water, rather it
was a stream of 32 bit integers!
Getting super excited, he sat by the stream and kept observing as the numbers kept coming.
To his surprise, after coming out the numbers kept disappearing after a while! He asked Paka,
the biggest tree by the stream, why the numbers were disappearing, and Paka replied that
each number of the stream comes with an expiration time. Beyond its expiration point, that
number gets eaten by the forest monster immediately. Each number has its own expiration
time, and Paka offered that, as each number comes out, he will let Oregon know the
expiration time of the number instantly. In exchange, sometimes Oregon will have to
calculate the K’th smallest number of the numbers that has not expired yet, where K will be
given by Paka.
Oregon has recently signed up for ICPC Regional contest, so he thinks the deal Paka offered
will be great for his practice. So let’s help Oregon with his regional al preparation. :)
Input:
Input starts with an integer T, then T cases follow.
Each case starts with an integer, which represents the number of events E. Then E lines
follow, each with one event.
Each event is a list of integers separated by spaces. A line of an event will be one of the
following two types:
1. OP( = 1): CURRENT_TIMESTAMP VALUE END_TIMESTAMP
This event starts with 1 which denotes the event type, followed by 3 integers:
a. CURRENT_TIMESTAMP: the current timestamp
b. VALUE: the value of the stream
c. END_TIMESTAMP: the timestamp where this value will expire.
2. OP( = 2): CURRENT_TIMESTAMP K
This event starts with 2 which denotes the event type, followed by 2 integers:
a. CURRENT_TIMESTAMP: the current timestamp
b. K: the position for the value that Paka is asking for.
Explanation:
Time is represented as a sequence of timestamps, which are 32 bit integers, the greater the
timestamp implies the later the time. CURRENT_TIMESTAMP is the timestamp of a
number coming out of the stream, or the timestamp of a query given by Paka. In the given
inputs, the CURRENT_TIMESTAMPS will be strictly increasing between consecutive
events.

And a number cannot expire before coming out of the stream, hence END_TIMESTAMP >=
CURRENT_TIMESTAMP.
Constraints:
1. 1 <= T <= 100
2. 1 <= E <= 10^5
3. 1 <= CURRENT_TIMESTAMP <= END_TIMESTAMP <= 10^9
4. 1 <= VALUE <= 10^6
5. 1 <= K <= 10^9
Output:
For each case, print the case number first. Followed by one line per event of type 2 for the
case. For each event of type 2, print one integer, the K’th smallest number currently in the
stream. Events are in the stream at time t if they entered the stream at time <= t, and their
END_TIMESTAMP value is >= t. If no such number exists, then print -1.
Sample Input/Output
Input Output
1
10
1 1 10 7
1 2 9 4
2 4 1
1 5 2 6
2 6 2
2 7 2
1 8 2 20
1 9 1 15
1 10 3 13
2 11 3
Case 1:
9
10
-1
3

 

一、原题地址

点我传送

 

二、大致题意

给出两种操作op:

①、1 x val y。表示在[ x , y ]范围的时间内,val会显示出来。即在y时间之后该数字val会消失。

②、2 x K 。表示询问在时间x时,显示出来的第k大的数为多少并输出,如果没有这样的数则输出-1.

注意,题目保证给出的x值一定单调递增

 

三、大致思路

本来想着是这一定是用可持久化的数据结构去做的,可是码力太弱,不知道怎么区间地更新版本。后来看到了dalao们的代码,如果先把时间排序,按照时间点来进行增加一个数,查询一个数,删除一个数的操作,那么剩下的就只需要维护当前的时间显示的数字个数就好了。然后改了改线段树的板子,好像看起来像个划分树了?关键是这种离散+类似于离线的操作,非常巧妙。

G++17 跑了2800ms左右,挤一挤过去了。

 

 

四、代码

#include<cstdio>
#include<map>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#include<set>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;


int T,n;
int Size,tot;
struct Node
{
    int Time,Value,Type,id;
    Node(){}
    Node(int _T,int _V,int _ty)
    {
        Time=_T;Value=_V;Type=_ty;
    }
    bool operator <(Node b)const
    {
        if(Time!=b.Time)return Time<b.Time;
        else return Type<b.Type;
    }
}Que[100005*2];
int h[100005*2],ans[100005];

const int maxn = 200005 * 4;	//线段树范围要开4倍
struct Tree
{
	int l, r, sum,real_val;
};
Tree node[maxn];

void PushUp(int i)
{
	node[i].sum = node[i << 1].sum + node[(i << 1) | 1].sum;
}

void build(int i, int l, int r)
{
	node[i].l = l; node[i].r = r;
	if (l == r)
	{
		node[i].sum = 0;
		node[i].real_val=h[l];
		return;
	}
	int mid = (l + r) / 2;
	build(i << 1, l, mid);
	build((i << 1) | 1, mid + 1, r);
	PushUp (i);
}


void add(int i, int k, int v)
{
	if (node[i].l == k&&node[i].r == k)//因为更改的单点,所以左右端点均和k相等
	{
		node[i].sum += v;
		return;
	}
	int mid = (node[i].l + node[i].r) / 2;
	if (k <= mid) add(i << 1, k, v);
	else add((i << 1) | 1, k, v);
	PushUp (i);
}


int Query(int i,int k)
{
    if (node[i].l == node[i].r )
		return node[i].real_val;
    if(node[i<<1].sum>=k)return Query(i<<1,k);
    else return Query(i<<1|1,k-node[i<<1].sum);
}

int main()
{
    scanf("%d",&T);
    int Ca=1;
    while(T--)
    {
        tot=Size=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            ans[i]=-inf;
            int op,curr_time,val;
            scanf("%d %d %d",&op,&curr_time,&val);
            if(op==1)
            {
                int end_time;scanf("%d",&end_time);
                Que[++Size]=Node(curr_time,val,1);//1表示加入数
                Que[++Size]=Node(end_time,val,3);//3表示删除数
                h[++tot]=val;
            }
            else
            {
                Que[++Size]=Node(curr_time,val,2);//2是查询
            }
            Que[Size].id=i;
        }
        sort(Que+1,Que+1+Size);//离线按照时间序排好
        //注意!增加操作是在查询之前的,因为边界也需要被计算在内


        sort(h+1,h+1+tot);
        tot=unique(h+1,h+1+tot)-(h+1);//hash处理值

        build(1,1,tot);
        for(int i=1;i<=Size;i++)
        {

            int pos=lower_bound(h+1,h+1+tot,Que[i].Value)-h;
            if(Que[i].Type==1)add(1,pos,1);

            else if(Que[i].Type==3)add(1,pos,-1);

            else
            {
                if(node[1].sum<Que[i].Value)ans[Que[i].id]=-1;
                else ans[Que[i].id]=Query(1,Que[i].Value);
            }
            //printf("**%d %d  %d\n",Que[i].Time,node[1].sum,Que[i].Type);
        }
        printf("Case %d:\n",Ca++);
        for(int i=1;i<=n;i++)
        {
            if(ans[i]!=-inf)printf("%d\n",ans[i]);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值