HDU 4046 Panda(线段树)

题目大意:在一串字符串中某个区间查询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;
}
时间: 2024-10-28 19:43:11

HDU 4046 Panda(线段树)的相关文章

HDU ACM 4046 Panda 线段树或者树状数组

分析:该題可以用线段树做,也可以用树状数组做:感觉树状数组容易一些,这里就用树状数组了.这里保存字符数组的下标从1开始,树状数组初始化从3开始,因为只有大于等于3使才可能有符合要求的字串出现,最终计算L到R区间的个数时要用getsum(R)-getsum(L+1),因为可能有符合要求的str[L-1],str[L],str[l+1]也被算进去了,实际上他并不在区间L到R内.更新时要注意三种情况,POS,POS+1,POS+2处的都会受影响. #include<iostream> using n

HdU 4046 Panda 段树

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4046 意甲冠军:到了bw组成的长度为n的字符串(n<=50000).有m次操作(m<=10000),每次操作是询问一段范围内wbw的个数.或者改变一个字符成为w或b. 思路:建一棵线段树,每一个结点记录的是从L到R以每一个i为最左边的字母的总共的wbw的个数,单点更新的时候要更新三个点. 代码: #include <iostream> #include <cstdio> #in

hdu 4046 Panda(树状数组)

1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 6 const int N = 50007; 7 8 int tree[N], n; 9 char str[N]; 10 11 int lowbit(int x) 12 { 13 return (x & -x); 14 } 15 16 void update(int pos, int

HDU—4046 Panda (线段树)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4046 题意:给出一个字符串,统计这个字符串任意区间中"wbw"出现的次数. 规定两种操作,一是查询任意区间"wbw"出现次数:二是修改某一位置的字符. 分析:比较明显的线段树,单点更新,区间查询. 线段树记录的信息是区间中出现"wbw"字符的个数,线段树的叶子节点[i,i]记录字符串str中 str[i-2][i-1][i]是否是"wbw&qu

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

HDU 1828 Picture 线段树+扫描线

题意:给你一些矩形的左上角点的坐标和右下角点的坐标,求周长并 最显而易见的思路就是对于x轴和y轴做两次扫描线,对于负数的坐标进行离散化.每次增加的值是线段变化量的绝对值.具体写法和求面积并的差不多. #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define lson rt << 1 , l , m

HDU 1542 Atlantis(线段树扫描线)

http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6788    Accepted Submission(s): 2970 Problem Description There are several ancient Greek

POJ 1177/HDU 1828 picture 线段树+离散化+扫描线 轮廓周长计算

求n个图矩形放下来,有的重合有些重合一部分有些没重合,求最后总的不规则图型的轮廓长度. 我的做法是对x进行一遍扫描线,再对y做一遍同样的扫描线,相加即可.因为最后的轮廓必定是由不重合的线段长度组成的,这样理论上是对的 要注意处理高度相同的线段,把底边优先处理(在代码里就是f标记为1的线段),因为若是一个矩形的底边和另一个矩形的上边重合,则这个轮廓肯定不能算 不过POJ和HDU的数据好像都比较弱,我没进行上面的细节处理也AC了,不过一个很简单的数据就会不对,所以还是要处理一下才是真正正确的代码 我

hdu 1542 Atlantis(线段树&amp;扫描线&amp;面积并)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6386    Accepted Submission(s): 2814 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i