HDU 4046 Panda(RMQ 线段树 树状数组)

题目大意:在一串字符串中某个区间查询wbw的数目,更新某个位置的字符

思路:线段树,每个枝结点记录以这个点为中心的字符是不是wbw,所以每次某个位置更新的时候,左右两个位置均要更新

而且查询的时候某个区间的wbw的个数,位于边界的字符的值不能算在内

用树状数组编程难度会降低

//561MS 3400K 3373 B 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

#define RR(x) (x<<1|1)
#define LL(x) (x<<1)
const int M =50000+5000;
int n,m;
char str[M];
int rts[M];//每个字符位置对应线段树根结点的位置
struct node
{
    int l,r;
    int sum;
    int mid()
    {
        return (l+r)>>1;
    }
};
inline bool ok(int pos)
{
    return (str[pos]=='b'&&str[pos-1]=='w'&&str[pos+1]=='w');
}
struct Segtree
{
    node tree[M<<2];
    void up(int rt)
    {
        tree[rt].sum=tree[LL(rt)].sum+tree[RR(rt)].sum;
    }
    void build(int l,int r,int rt)
    {
        tree[rt].l = l;
        tree[rt].r = r;
        if(l==r)
        {
            rts[l]=rt;
            if(l==0||l==n-1) tree[rt].sum=0;
            else tree[rt].sum = ok(l);
            return ;
        }
        int mid=tree[rt].mid();
        build(l,mid,LL(rt));
        build(mid+1,r,RR(rt));
        up(rt);
    }
    void update(int pos,char ch,int rt)
    {
        if(tree[rt].l==tree[rt].r)
        {
            str[pos]=ch;
            if(pos==0||pos==n-1) tree[rt].sum=0;
            else tree[rt].sum= ok(pos);
            return ;
        }
        int mid=tree[rt].mid();
        if(pos<=mid) update(pos,ch,LL(rt));
        else update(pos,ch,RR(rt));
        up(rt);
    }
    int query(int L,int R,int rt)
    {
        if(L<=tree[rt].l&&tree[rt].r<=R)
        {
            int tmp=0;
            if(L==tree[rt].l&&tree[rts[L]].sum) tmp++;
            if(R==tree[rt].r&&tree[rts[R]].sum) tmp++;
            if(L==R) tmp=tree[ rts[R] ].sum ;
            return tree[rt].sum-tmp;
        }
        int sum=0;
        int mid=tree[rt].mid();
        if(L<=mid) sum+=query(L,R,LL(rt));
        if(R>mid) sum+=query(L,R,RR(rt));
        return sum;
    }
}seg;
int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        printf("Case %d:\n",cas);
        scanf("%d%d",&n,&m);
        scanf("%s",str);

        seg.build(0,n-1,1);
        while(m--)
        {
            int op;
            scanf("%d",&op);
            if(op==0)
            {
                int l,r;
                scanf("%d%d",&l,&r);
                printf("%d\n",seg.query(l,r,1));
            }
            else
            {
                int p;
                char ch;
                scanf("%d %c",&p,&ch);
                seg.update(p,ch,1);
                if(p-1>0) seg.update(p-1,str[p-1],1);
                if(p+1<n-1) seg.update(p+1,str[p+1],1);
 
            }
        }
    }
    return 0;
}


树状数组:

//421MS 1928K 1865 B C++ 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M= 50000+5000;
char str[M];
int sum[M];
int n,m;
bool book[M];
inline int lowbit(int x)
{
    return x&-x;
}
void update(int p,int val)
{
    for(int i=p;i<M;i+=lowbit(i))
    {
        sum[i]+=val;
    }
}
int getsum(int rt)
{
    int ans=0;
    for(int i=rt;i>0;i-=lowbit(i))
        ans+=sum[i];
    return ans;
}
inline bool ok(int p)
{
    return (str[p-1]=='w'&&str[p]=='b'&&str[p+1]=='w');
}
void up(int p)
{
    if(p<=1||p>=n) return ;
    if(book[p]<ok(p))
    {
        book[p]=ok(p);
        update(p,1);
    }
    else if(book[p]>ok(p))
    {
        book[p]=ok(p);
        update(p,-1);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        printf("Case %d:\n",cas);
        scanf("%d%d",&n,&m);
        scanf("%s",str+1);
        book[1]=book[n]=0;
        memset(sum,0,sizeof(sum));
        for(int i=2;i<n;i++)
        {
            book[i]=ok(i);
            if(book[i])update(i,book[i]);
        }
        while(m--)
        {
            int op;
            scanf("%d",&op);
            if(op==0)
            {
                int l,r;
                scanf("%d%d",&l,&r);
                l++,r++;
                int ans=getsum(r)-getsum(l-1);
                int tmp=book[l]+book[r];
                if(l==r) tmp=book[l];
                ans-=tmp;
                printf("%d\n",ans);
            }
            else
            {
                int p;
                char ch;
                scanf("%d %c",&p,&ch);
                p++;
                str[p]=ch;
                up(p);
                up(p-1);
                up(p+1);
            }
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值