hdu 4046 Panda(线段树+单点更新)

原题友情链接直通车~点击此处查看原题~

2011年北京赛区网络赛的一道水题..............按照自己现在的水平还算不上所谓的水题。哭

考察:区间更新跟区间查询,线段树or树状数组。

这里我用的是线段树。

题意:一个小盆友要给他的女神示爱,但是他要赶时间,没时间写那么多,写的信上只有“w”和''b"。给出一个规定,出线连续的字符串是wbw时表示一个Love。第一行输入一个T,

表示测试数据的组数。紧接着输入n,m。分别表示这封信上有n个字和下面有m个操作。

m个操作中有两种情况。

Type 0: answer how many love between L and R. (0<=L<=R<n)
Type 1: change the kth character to ch(0<=k<n and ch is ‘b’ or ‘w’) 也就是说 “0”表示查询,“1”表示更新
这个题跟容易想的到线段树或者是树状数组来解。有着很明显的区间操作要求。然后,这个题最大的难点就在于叶子结点value值代表的含义。

博主在一开始做的时候就是一直想不到如何来建树。看大神的解答是若letter[l] == 1,则表示letter[l-2],letter[l-1],letter[l]可以达到上面的要求。

有人会问,这么查询的话正好从l开始,不是就错了吗?这里有一个巧妙的处理是在查询的时候查询的区间是(l+2,r)。就避免的上述问题。

最后一点就是更新了。当你更新一点后,因为是用第三个位置来表示这段字符串是否符合要求。在更新完l点也要更新l+1,跟l+2,的值。所以每次更新最多会出现三次单点更新操作。(想想看,为什么?当l+1,或者是l+2越出n的范围就不用在更新了)

还有一个小细节就是当前处理的区间长度不满足3的时候直接输出0,这个是显然的。

具体的实现过程看代码。

#include<cstdio>
#include<cstring>
#define ll(x) (x)<<1
#define rr(x) ll(x)|1
using namespace std;
const int Maxsize = 50010;
typedef struct
{
    int l,r,value;
} Tree;
Tree tree[Maxsize<<2];
char letter[Maxsize];
void Pushup(int v)
{
    tree[v].value = tree[ll(v)].value + tree[rr(v)].value;
}
void build(int v,int l,int r)/*建树*/
{							
    tree[v].l = l;
    tree[v].r = r;
    tree[v].value = 0;
    if(l == r)
    {
        if( l <= 2)
        {
            tree[v].value = 0;
            return;
        }
        if( letter[l] == 'w' && letter[l-1] == 'b' && letter[l-2] == 'w')
        {
            tree[v].value = 1;
        }
        else
        {
            tree[v].value = 0;
        }
        return;
    }
    int mid = ( l + r)>>1;
    build(ll(v),l,mid);
    build(rr(v),mid+1,r);
    Pushup(v);
}
void update(int v,int k,char t)/*更新*/
{
    if(tree[v].l == k && tree[v].r == k)
    {
        letter[k] = t;
        if( k <= 2)return;
        if(letter[k] == 'w' && letter[k-1] == 'b' && letter[k-2] == 'w')
        {
            tree[v].value = 1;
        }
        else
        {
            tree[v].value = 0;
        }
        return;
    }
    int mid = (tree[v].l + tree[v].r)>>1;
    if(k <= mid)
    {
        update(ll(v),k,t);
    }
    else
    {
        update(rr(v),k,t);
    }
    Pushup(v);
}
int query(int v,int l,int r)/*区间查询*/
{
    if(tree[v].l == l && tree[v].r == r)
    {
        return tree[v].value;
    }
    int mid = (tree[v].l + tree[v].r)>>1;
    if(r <= mid)
    {
        return query(ll(v),l,r);
    }
    else
    {
        if(l > mid)
        {
            return query(rr(v),l,r);
        }
        else
        {
            return query(ll(v),l,mid) + query(rr(v),mid+1,r);
        }
    }
}
int main()
{
    int ncase,casen = 0;/*ncase表示测试数据的组数,casen表示当前是第几组*/
    scanf("%d",&ncase);
    while(ncase--)
    {
        memset(tree,0,sizeof(tree));
        int n,m;
        scanf("%d %d",&n,&m);
        letter[0] = 0;
        scanf("%s",letter+1);/*字符串下标从1开始*/
        build(1,1,n);
        int k,a,b;
        char t[2];
        printf("Case %d:\n",++casen);
        for(int i = 0 ; i < m ; i++)
        {
            scanf("%d",&k);
            if(!k)
            {
                scanf("%d %d",&a,&b);
                if(b-a < 2 || b < 2)/*不满足三个字母的最基本条件*/
                {
                    printf("0\n");
                }
                else
                {
                    printf("%d\n",query(1,a+3,b+1));/*查询*/
                }
            }
            else
            {
                scanf("%d %s",&a,t);
                update(1,a+1,t[0]);/*依次进行单点更新*/
                if( a+1 < n)
                {
                    update(1,a+2,letter[a+2]);
                }
                if( a+2 < n)
                {
                    update(1,a+3,letter[a+3]);
                }
            }
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值