hdu 4967 Handling the Past 线段树 2014 Multi-University Training Contest 9-1008

题意:

给定一系列push,pop,peak操作。每各操作都有一个不同的时间戳。下面介绍操作;

push w t,将w加入栈,t为时间戳。

pop t,将最后一个元素取出,t为时间戳。

peak t,输出栈顶的元素,t为时间戳。若不存在,输出-1

现在进行一个操作,时间戳为t1,由三个步骤,

1)将所有时间戳大于t1的操作还原。

2)执行该操作。

3)重新执行被还原的操作。


题解:

先将时间戳从小到大排列后离散化,然后根据时间戳建线段树。线段树结点由两个元素,sum表示该段的所有元素和,rmax表示该段的最大后缀和。上述题意可以转换成push操作就是讲对应时间戳+1,pop将对应时间戳-1,peak t操作就是求最大的t‘使得,[t',t)的元素和大于0。

在查询的过程中,我们从查询的时间戳t开始,从右到左查询,每次不存在时用len记录已经查询过的区间和。每次判断下len+这段区间的最大后缀和是否大于0,是的话继续查询,不是的话更新len,直至查询到叶子节点。那么叶子节点就是我们要求的时间戳,其对应的w就是所求值了。




代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cctype>
using namespace std;

#define lc (c<<1)
#define rc (c<<1|1)
const int maxn=5e4+10;
struct node{
    int l,r,rmax,sum;
}e[maxn*4];
struct op{
    char ch[10];
    int w,t;
}f[maxn];
int val[maxn*4],discrete[maxn],tt,len;
int get_id(int x)
{
    return lower_bound(discrete,discrete+tt,x)-discrete;
}
void build(int a,int b,int c)
{
    e[c].l=a;e[c].r=b;
    e[c].rmax=e[c].sum=0;
    if(a==b)return ;
    int mid=(a+b)>>1;
    build(a,mid,lc);
    build(mid+1,b,rc);
}
void update(int a,int b,int c,int d)
{
    if(e[c].l==a&&e[c].r==b)
    {
        val[c]=d;
        if(d>=0)
        {
            e[c].sum=e[c].rmax=1;
        }
        else
        {
            e[c].sum=-1;
            e[c].rmax=0;
        }
        return ;
    }
    int mid=(e[c].l+e[c].r)>>1;
    if(b<=mid)update(a,b,lc,d);
    else if(a>mid)update(a,b,rc,d);
    e[c].sum=e[lc].sum+e[rc].sum;
    e[c].rmax=max(e[rc].rmax,e[rc].sum+e[lc].rmax);
}
int query(int a,int c)
{
    if(e[c].r<=a)
    {
        int s=len+e[c].rmax;
        if(s<=0)
        {
            len+=e[c].sum;
            return -1;
        }
    }
    if(e[c].l==e[c].r)return val[c];
    int mid=(e[c].l+e[c].r)>>1;
    if(mid<a)
    {
        int ans=query(a,rc);
        if(ans!=-1)return ans;
    }
    return query(a,lc);
}
void readchar(char *s)
{
    int i=0;
    char ch=getchar();
    while(!(ch<='z'&&ch>='a'))ch=getchar();
    while(ch<='z'&&ch>='a')
    {
        s[i++]=ch;
        ch=getchar();
    }
    s[i]='\0';
}
int readint()
{
    int x=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}
int main()
{
    //freopen("D:\\1008.in","r",stdin);
    //freopen("C:\\Documents and Settings\\Administrator\\桌面\\false.out","w",stdout);
    int n,tot=0;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        int i,j,k;
        tt=0;
        for(i=0;i<n;i++)
        {
            //scanf("%s",f[i].ch);
            readchar(f[i].ch);
            if(f[i].ch[1]=='u')
            {
                //scanf("%d%d",&f[i].w,&f[i].t);
                f[i].w=readint();
                f[i].t=readint();
            }
            else //scanf("%d",&f[i].t);
                f[i].t=readint();
            if(f[i].ch[1]!='e')discrete[tt++]=f[i].t;
        }
        sort(discrete,discrete+tt);
        build(0,tt-1,1);
        printf("Case #%d:\n",++tot);
        for(i=0;i<n;i++)
        {
            int id=get_id(f[i].t);
            if(f[i].ch[1]=='o')update(id,id,1,-1);
            else if(f[i].ch[1]=='u')update(id,id,1,f[i].w);
            else
            {
                if(id==0)printf("-1\n");
                else
                {
                    len=0;
                    printf("%d\n",query(id-1,1));
                }
            }
        }
    }
    return 0;
}


你可能感兴趣的:(线段树)