hdu1540(线段树区间合并)

这题是个很恶心的题,区间合并是比较裸的。但这题有的东西没有叙述清楚,题目上说的是一组数据,但测试数据却是多组数据,这题还有几点需要注意的,一是一个村庄可以被摧毁多次,当然如果你代码写得好,这点也是没关系的。我当时用b^=1来表示每次变化,但如果;连续摧毁两次,我的结果就相当于重建了,后来只有老老实实的写了。所以大家得注意到类似多多次摧毁的问题。后来都改过来了却一直1000多ms wa,我想可能是有些小细节没注意到,又是摧毁的问题,如果村子摧毁了,那么这个村子就没有相连的村子。改过来后果断a了。楼主水平比较低,查询时写了两个查询函数,一是查询村子左边连续的个数,一是右边连续的个数。网上看别人大神的代码,run的时间比我少,需要的空间比我少,代码长度比我少。。。真的是得继续努力!

#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<stack>
#define MAX 50100
using namespace std;
int n,m;
typedef struct
{
    int left,right,lnum,rnum,mid,len;
    void get()
    {
        mid=(right+left)>>1;
        len=right-left+1;
    }
    void set(int a)
    {
        lnum=rnum=a;
    }
}P;
P p[MAX*4];
int d[MAX];
void push_up(int k)
{
    int lt=k<<1,rt=lt+1;

    p[k].lnum= p[lt].lnum== p[lt].len? p[lt].lnum+ p[rt].lnum: p[lt].lnum;
    p[k].rnum= p[rt].rnum== p[rt].len? p[rt].rnum+ p[lt].rnum: p[rt].rnum;
}
void build(int k,int l,int r)
{
    p[k].left=l;
    p[k].right=r;
    p[k].get();
    if(l==r)
    {
        p[k].set(1);
        return;
    }
    build(k<<1,l, p[k].mid);
    build(k<<1|1, p[k].mid+1,r);
    push_up(k);
}
void update(int k,int a,int f)
{
    if( p[k].len==1)
    {
        d[a]=f;
        p[k].set(d[a]);
        return;
    }
    if(a<= p[k].mid)
        update(k<<1,a,f);
    else
        update(k<<1|1,a,f);
    push_up(k);
}
int query_left(int k,int l,int a)
{
    if( p[k].left==l&& p[k].right==a)
            return  p[k].rnum;
    if( p[k].mid>=a)
        return query_left(k<<1,l,a);
    else
    {
        int temp=query_left(k<<1|1, p[k].mid+1,a);
        return  temp==a- p[k].mid? temp+ p[k<<1].rnum:temp;
    }
}
int query_right(int k,int a,int r)
{
    if( p[k].left==a&& p[k].right==r)
        return  p[k].lnum;
    if( p[k].mid<a)
        return query_right(k<<1|1,a,r);
    else
    {
        int temp =query_right(k<<1, a, p[k].mid);
        return temp== p[k].mid-a+1? temp+ p[k<<1|1].lnum:temp;
    }
}
int main()
{
    char ch;
    int a;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
    stack<int> s;
    build(1,1,n);
    fill(d+1,d+1+n,1);
    while(m--)
    {
        cin>>ch;
        if(ch=='D')
        {
            scanf("%d",&a);
            s.push(a);
            update(1,a,0);
        }
        if(ch=='Q')
        {
            scanf("%d",&a);
            if(d[a])
                printf("%d\n",a!=n?query_left(1,1,a)+query_right(1,a+1,n):query_left(1,1,a));
            else
                printf("0\n");
        }

        if(ch=='R')
        {
            if(s.empty())
                continue;
            a=s.top();
            s.pop();
            update(1,a,1);
        }
    }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值