Hdu 4967 Handling the Past (线段树)

题目大意:

关于网络阻塞命令延迟的处理。

命令就分为三种对栈的处理。

但是如果接收到一个操作,它后面的操作都要先取消不做,再做这个操作,再做之前取消了的操作。

思路分析:

题目也就转化成了,给出一个时间t接收到peak操作,找到第一个最大的 l ,使得 sum[l - t] > 0...

然后的问题我们就是如何确定最大的l。

我们记录sum的同时再记录一个右边最大。

然后我们在查询的时候,就通过右边最大和sum ,确定区间。

当s==e的时候就是所求的。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define lson num<<1,s,mid
#define rson num<<1|1,mid+1,e
#define maxn 50005
using namespace std;
typedef long long ll;
struct node
{
    char type;
    int t,val;
}save[maxn];

int res[maxn<<2];
int rsum[maxn<<2];
int id[maxn];

int n;
void pushup(int num)
{
    res[num]=res[num<<1]+res[num<<1|1];
    rsum[num]=max(rsum[num<<1|1],res[num<<1|1]+rsum[num<<1]);
}
void update(int num,int s,int e,int pos,int val,int tid)
{
    if(s==e)
    {
        res[num]+=val;
        rsum[num]+=val;
        id[s]=tid;
        if(val==-1)id[s]=0;
        return;
    }
    int mid=(s+e)>>1;
    if(pos<=mid)update(lson,pos,val,tid);
    else update(rson,pos,val,tid);
    pushup(num);
}
int query(int num,int s,int e,int l,int r)
{
    if(l<=s && r>=e)
        return res[num];
    int mid=(s+e)>>1;
    if(r<=mid)return query(lson,l,r);
    else if(l>mid)return query(rson,l,r);
    else return query(lson,l,mid)+query(rson,mid+1,r);
}
int peak(int num,int s,int e,int l,int r,int t)
{
    if(l<=s && r>=e)
    {
        if(s==e)
        {
            return id[s];
        }
        else {
            int mid=(s+e)>>1;
            if(rsum[num<<1|1]>t)
            {
                int tmp = peak(rson,l,r,t);
                if(tmp)return tmp;
            }
            else if(rsum[num<<1]>t-res[num<<1|1]){
                int tmp = peak(lson,l,r,t-res[num<<1|1]);
                if(tmp)return tmp;
            }
        }
        return 0;
    }
    int mid=(s+e)>>1;
    if(r<=mid)
    {
        int tmp = peak(lson,l,r,t);
        if(tmp)return tmp;
    }
    else if(l>mid){
        int tmp = peak(rson,l,r,t);
        if(tmp)return tmp;
    }
    else {
        int tmp = peak(rson,mid+1,r,t);
        if(tmp)return tmp;
        tmp = peak(lson,l,mid,t-query(1,1,n,mid+1,r));
        if(tmp)return tmp;
    }
}
int x[maxn];
int main()
{
    int CASE=1;
    while(scanf("%d",&n)!=EOF && n)
    {
        memset(res,0,sizeof res);
        memset(rsum,0,sizeof rsum);
        memset(id,0,sizeof id);

        printf("Case #%d:\n",CASE++);
        char str[10];
        for(int i=1;i<=n;i++)
        {
            int v,time;
            scanf("%s",str);
            if(str[1]=='u')scanf("%d%d",&v,&time);
            else scanf("%d",&time);
            save[i].type=str[1];save[i].val=v;save[i].t=time;
            x[i]=save[i].t;
        }

        sort(x+1,x+1+n);

        for(int i=1;i<=n;i++)
            save[i].t=lower_bound(x+1,x+1+n,save[i].t)-x;

        for(int i=1;i<=n;i++)
        {
            if(save[i].type=='u')
                update(1,1,n,save[i].t,1,i);
            else if(save[i].type=='o')
                update(1,1,n,save[i].t,-1,i);
            else {
                int pos = save[i].t-1;
                if(pos<1)puts("-1");
                else {
                    if(query(1,1,n,1,pos)>0)
                    {
                        printf("%d\n",save[peak(1,1,n,1,pos,0)].val);
                    }
                    else puts("-1");
                }
            }
        }
    }
    return 0;
}

Hdu 4967 Handling the Past (线段树)

时间: 2024-10-12 20:45:41

Hdu 4967 Handling the Past (线段树)的相关文章

hdu 4967 Handling the Past 线段树,最右正值区间

最后一场多校,又被吊打. 最近学了一些莫名其妙的算法,然而最简单的线段树都写不好.(政神1小时秒杀的题目我改了4小时.) 还是静下心来,学好用好每一种算法. hdu 4967 Handling the Past 看了题解.很巧妙的做法. 利用线段树记录一个值rmax=max{左儿子的rmax+右儿子的sum,右儿子的rmax}. 通过这个值可以快速找到 总和为正值的最右位置. 需要注意的是,当递归到左儿子时,sum要加上右儿子中在查询区间内的sum.我的程序中用了一个带引用的tsum变量完成了这

HDU 4967 Handling the Past

题意: 你有一个栈  一些操作发生在栈上  包括进栈.出栈.询问栈顶  每个操作有一个独一无二的时间  当操作读进来时  要把之前处理的本该在本操作之后的操作全撤销  接着完成现在的操作  再把撤销的操作重做一遍  每次询问操作输出栈顶元素 思路: 由于时间唯一  那么可以用时间来对应插入的元素以及操作的类型  所以首先离散化时间(这里不去掉重复也行) 然后我们把push当作+1  pop当作-1  就可以维护栈内元素个数了  再考虑peak询问  即是询问"最靠后的后缀和>0的位置&qu

hdu 1754 I Hate It 线段树 点修改

// hdu 1754 I Hate It 线段树 点修改 // // 不多说,裸的点修改 // // 继续练 #include <algorithm> #include <bitset> #include <cassert> #include <cctype> #include <cfloat> #include <climits> #include <cmath> #include <complex> #i

HDU 4902 Nice boat(线段树 区间更新)

Nice boat 大意:给你一个区间,每次可以进行两种操作,1:把区间中的数全都变成x  2:把区间中大于x的数变成gcd(a[i], x),最后输出序列. 思路:线段树成段更行,用num数组的叶子存储数据,节点当作lazy来使用. 1 #include <stdio.h> 2 const int maxn = 100005; 3 4 int num[maxn<<2]; 5 6 int gcd(int a, int b){ 7 return b?gcd(b, a%b):a; 8

hdu 4893 Wow! Such Sequence!(线段树)

题目链接:hdu 4983 Wow! Such Sequence! 题目大意:就是三种操作 1 k d, 修改k的为值增加d 2 l r, 查询l到r的区间和 3 l r, 间l到r区间上的所以数变成最近的斐波那契数,相等的话取向下取. 解题思路:线段树,对于每个节点新增一个bool表示该节点以下的位置是否都是斐波那契数. #include <cstdio> #include <cstring> #include <cstdlib> #include <algor

hdu 2852 KiKi&#39;s K-Number (线段树)

hdu 2852 题意: 一个容器,三种操作: (1) 加入一个数 e (2) 删除一个数 e,如果不存在则输出 No Elment! (3) 查询比a大的数中的第k小数,不存在就输出 Not Find! 解法: 关于第三点,可以先查询小于等于a的数的个数cnt,然后直接查询第cnt+k小数就行了 . 二分+树状数组 或者 主席树(有点杀鸡用牛刀的感觉 ...) 也是可以做的  _(:з」∠)_ code:线段树 1 #include <iostream> 2 #include <cst

Bestcoder round #65 &amp;&amp; hdu 5592 ZYB&#39;s Premutation 线段树

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 175    Accepted Submission(s): 74 Problem Description ZYB has a premutation P,but he only remeber the reverse log of each prefix of the premutat

hdu 1166 敌兵布阵 线段树 点更新

// hdu 1166 敌兵布阵 线段树 点更新 // // 这道题裸的线段树的点更新,直接写就可以了 // // 一直以来想要进线段树的坑,结果一直没有跳进去,今天算是跳进去吧, // 虽然十分简单,十分的水,继续加油 #include <algorithm> #include <bitset> #include <cassert> #include <cctype> #include <cfloat> #include <climits

HDU 1698 Just a Hook (线段树,区间更新)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 17214    Accepted Submission(s): 8600 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing f