您的位置:首页 > 其它

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

2013-08-06 09:47 453 查看
原题友情链接直通车~点击此处查看原题~

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: