Codeforces Contest 1089 problem K King Kog's Reception —— 线段树求当等队列所需要的时间

King Kog got annoyed of the usual laxity of his knights — they can break into his hall without prior notice! Thus, the King decided to build a reception with a queue where each knight chooses in advance the time when he will come and how long the visit will take. The knights are served in the order of the recorded time, but each knight has to wait until the visits of all the knights before him are finished.

Princess Keabeanie wants to see her father. However, she does not want to interrupt the knights so she joins the queue. Unfortunately, the knights change their minds very often — they can join the queue or cancel their visits. Please help the princess to understand how long she will have to wait until she sees her father if she enters the queue at the specified moments of time given the records at the reception.

Input
The first line of the input contains a single integer q (1≤q≤3⋅105) — the number of events. An event can be of three types: join, cancel, or query.

Join “+ t d” (1≤t,d≤106) — a new knight joins the queue, where t is the time when the knight will come and d is the duration of the visit.
Cancel “- i” (1≤i≤q) — the knight cancels the visit, where i is the number (counted starting from one) of the corresponding join event in the list of all events.
Query “? t” (1≤t≤106) — Keabeanie asks how long she will wait if she comes at the time t.
It is guaranteed that after each event there are no two knights with the same entrance time in the queue. Cancel events refer to the previous joins that were not cancelled yet.

Keabeanie can come at the same time as some knight, but Keabeanie is very polite and she will wait for the knight to pass.

Output
For each query write a separate line with the amount of time Keabeanie will have to wait.

Example
inputCopy
19
? 3

  • 2 2
    ? 3
    ? 4
  • 5 2
    ? 5
    ? 6
  • 1 2
    ? 2
    ? 3
    ? 4
    ? 5
    ? 6
    ? 7
    ? 9
  • 8
    ? 2
    ? 3
    ? 6
    outputCopy
    0
    1
    0
    2
    1
    3
    2
    1
    2
    1
    0
    0
    2
    1
    1

题意:

有一些骑士要去见国王,公主也要见国王
+ t d表示一个骑士在t分钟的时候去见国王,要见d分钟。
? t 表示如果公主在t时间见国王,要等多久
- i 表示取消输入序列的第i个想要见国王的骑士
国王每次只能见一个人,其他人要在外面等着,如果公主和一个骑士同时到达,那么骑士先等。

题解:

一开始题意读错了,想了很久。看了别人的博客才知道正确题意。
能想到一点,就是公主是在她去的时候的队列的最后一个骑士见完之后才去见得国王,那么就是某个骑士在t1的时间开始的队列到公主去的时间t2这段区间内所有骑士的见的时间的和再加上t1,减去t2就是公主等待的时间。那么我们线段树需要只掉某一个区间内所有骑士见国王的总时间。但是枚举t2之前的所有点肯定是会超时的,那么我们就需要记录1到t2之间的最大值,也就是等待队列的最大值,首先我们maxn[root]中存的是当前root下l的值,也就是从这个位置开始见国王的时间,对于前面的位置来说,只要它的时间加位置不超过后面的位置,那么它就不是最大值。举个例子:在这里插入图片描述
如果公主在绿色的线这里去见国王那么队列中有2和3,如果1骑士他见的时间是红色的线,未与2交,那么1骑士无论用多少时间,他的值都不会比2的开头大,所以这就不是最大值,如果是蓝色的,那么就是从1开始队列了。
如果公主是在紫色的位置,那么我们查询的时候,骑士1开始的队列最长也不会超过2这个位置本身的值,那么答案就是 p p p,然后再减上公主去的时间 p p p,就是0.
我们在计算答案的时候,由于是从左到右query的,那前面的ans需要加上当前root的sum值才表示从ans位置开始的队列最长值

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+5;
ll sum[N*4],maxn[N*4];
void pushup(int root)
{
    sum[root]=sum[root<<1]+sum[root<<1|1];
    maxn[root]=max(maxn[root<<1]+sum[root<<1|1],maxn[root<<1|1]);
}
void build(int l,int r,int root)
{
    if(l==r)
    {
        maxn[root]=l;
        return ;
    }
    int mid=l+r>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
    pushup(root);
}
void update(int l,int r,int root,int pos,ll val)
{
    if(l==r)
    {
        sum[root]+=val;
        maxn[root]+=val;
        return ;
    }
    int mid=l+r>>1;
    if(mid>=pos)
        update(l,mid,root<<1,pos,val);
    else
        update(mid+1,r,root<<1|1,pos,val);
    pushup(root);
}
ll ans;
void query(int l,int r,int root,int pos)
{
    if(r<=pos)
    {
        ans=max(ans+sum[root],maxn[root]);
        return ;
    }
    int mid=l+r>>1;
    query(l,mid,root<<1,pos);
    if(mid<pos)
        query(mid+1,r,root<<1|1,pos);
}
ll p[N],v[N];
int main()
{
    int q;
    scanf("%d",&q);
    build(1,N-1,1);
    for(int i=1;i<=q;i++)
    {
        char op[2];
        ll x,y;
        scanf("%s",op);
        if(op[0]=='+')
        {
            scanf("%lld%lld",&x,&y);
            update(1,N-1,1,x,y);
            p[i]=x,v[i]=y;
        }
        else if(op[0]=='-')
        {
            scanf("%lld",&x);
            update(1,N-1,1,p[x],-v[x]);
        }
        else
        {
            scanf("%lld",&x);
            ans=0;
            query(1,N-1,1,x);
            printf("%lld\n",max(ans-x,0ll));
        }
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值