hook+线段树(二)小结区间操作

来源:互联网 发布:C语言多个else if用法 编辑:程序博客网 时间:2024/06/05 09:23
 线段树(二)lazy区间操作
 学习数据结构的重点一定离不开线段树,虽然树状数组更为快捷,但线段树的灵活性无疑是非常高的。(不止我一个人觉得,有很多大神都觉得线段树可以优化很多题目)
下面以一道实际的lazy标记题目理清思想:
DOTA  ----------------------------------------------------------------------------(hook)
8 / 25Problem CHDU 1698成段更新(延迟标记) C - 成段更新(延迟标记)
Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit Status Practice HDU 1698

Description

In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length. 

Now Pudge wants to do some operations on the hook. 

Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks. 
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows: 

For each cupreous stick, the value is 1. 
For each silver stick, the value is 2. 
For each golden stick, the value is 3. 

Pudge wants to know the total value of the hook after performing the operations. 
You may consider the original hook is made up of cupreous sticks. 
 

Input

The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases. 
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations. 
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind. 
 

Output

For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example. 
 

Sample Input

1
10
2
1 5 2
5 9 3
 

Sample Output

Case 1: The total value of the hook is 24.





额,看到英文题是不是很给力,利用有道翻译(下面是翻译网址):
http://fanyi.youdao.com/WebpageTranslate?keyfrom=fanyi.web.index&url=http%3A%2F%2Facm.hdu.edu.cn%2Fshowproblem.php%3Fpid%3D1698&type=AUTO&action=FY_BY_CLICKBUTTON  稍稍为难一下大家!!直接来中文水平一下就下去了!

所以,稍稍解释一下吧,就是钩子由n个金属棒组成,初始都是x=1(铜),每次把一个区间[l,r]的金属棒变成一种新的金属棒。求更新完了之后,屠夫钩子的总价值(每一个金属棒的值加在一起)

简单的区间操作好像就可以吧(老实说,简单的区间操作是对于区间的每一个点都访问一次,回朔时更新父节点,这样的坏处是有些点在未访问的时候更新了多次,这样相当浪费时间,在高效算法里这种算法果断卡掉):
下面介绍lazy标记,pushdown函数的区间操作

建树(代码参考  '线段树(一)',建树的时候把lazy初始化);

void change(int i,int l,int r,int x)//从i出发,把区间[l,r]的值改为x
{
if(tree[i].lch>=l&&tree[i].rch<=R)/*节点i这个区间包含在要更新的区间内,直接更新父节点(待到需要访问的时候才向它的子节点更新,形象的说,老板让经理做事,经理先把要做的是记录下来,有一天老板要检查成果了(查询),经理马上把要做的事下方给部门总管,经理要检查成果时,总管慌忙把任务交给下面的员工)虽然这个比喻不是很恰当,不过在这里可以帮助我们更好的理解*/
{
tree[i].操作值---->更新.
tree[i].lazy操作x;
return ;
}
pushdown(i,tree[i].rch-tree[i].lch+1);//一般我定义pushdown(int i,int m)//m为区间长度,i为当前节点
int mid=(tree[i].lch+tree[i].rch)/2;
if(mid>=l)change(i*2,l,r,x);   //这么考虑吧,如果区间中间比要求区间左边大,说明该节点左子节点一定存在[l,r]的一个子区间 . 下面也是一样
if(mid<r)change(i*2+1,l,r,x);
tree[i].操作值----->更新

int query(int i,int l,int r)//查询区间值 
{
if(tree[i].lch>=l&&tree[i].rch<=r)return tree[i].操作值;//i的区间是一个子区间
pushdown(i,tree[i].rch-tree[i].lch+1);//下放lazy,有些区间可能还未更新,(因为有些用不到)
int mid=(tree[i].lch+tree[i].rch)/2;
int ans=0;
if(mid>=l)ans+=query(i*2,l,r);
if(mid<r)ans+=query(i*2+1,l,r);//道理同区间操作


是否对lazy还很疑惑;
看一下pushdown函数吧 
void pushdown(int i,int m)//m为区间长度
{
if(tree[i].lazy)//如果存在lazy(没有更新下放,需要更新下放)
{
tree[i*2].lazy操作tree[i].lazy(可能是等于,向这道题,也可能是累加)
tree[i*2+1].lazy操作tree[i].lazy;
tree[i*2].操作值---->更新
tree[i*2].操作值---->更新
tree[i].lazy=0;//最后一定记得改为空,表示已经下放过了,否则下次询问时仍然更新,可能会出错!
}


线段树最重要的就是这个lazy标记pushdown函数,不然就没什么难度!
这道题代码:
 
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
using namespace std;
int T;
void inin()
{
    freopen("hook.in","r",stdin);
    freopen("hook.out","w",stdout);
}
int n;
int q;
struct node
{
    int l,r,sum,lazy;
}tree[400000+100];
void pushdown(int i,int m)
{
    if(!tree[i].lazy)return ;
    tree[i*2].sum=tree[i].lazy*(m-m/2);
    tree[i*2+1].sum=tree[i].lazy*(m/2);
    tree[i*2].lazy=tree[i].lazy;
    tree[i*2+1].lazy=tree[i].lazy;
    tree[i].lazy=0;
}
void build(int i,int l,int r)
{
    tree[i].l=l;
    tree[i].r=r;
    if(l==r)
    {
        tree[i].sum=0;
        tree[i].lazy=1;
        return ;
    }
    int mid=(l+r)/2;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
    tree[i].lazy=1;
}
void add(int i,int x,int y,int z)      // [x,y]-->z
{
    int l=tree[i].l;
    int r=tree[i].r;
    if(l>=x&&r<=y)
    {
        tree[i].sum=(r-l+1)*z;
        tree[i].lazy=z;
        return ;
    }
    int mid=(l+r)/2;
    pushdown(i,r-l+1);
    if(mid>=x)add(i*2,x,y,z);
    if(mid<y)add(i*2+1,x,y,z);
    tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
}
int query(int i,int L,int R)
{
    int l=tree[i].l;
    int r=tree[i].r;
    if(l>=L&&r<=R)
    {
        return tree[i].sum;
    }
    int ans=0;
    pushdown(i,r-l+1);
    int mid=(l+r)/2;
    if(mid>=L)ans+= query(i*2,L,R);
    if(mid<R)ans+= query(i*2+1,L,R);
    return ans;
}
int main()
{
    scanf("%d",&T);
    for(int i=1;i<=T;i++)
    {
        scanf("%d",&n);
        build(1,1,n);
        scanf("%d",&q);
        for(int j=1;j<=q;j++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);  //[x,y]  -------->z
            add(1,x,y,z);
        }
        printf("Case %d: The total value of the hook is %d.\n",i,query(1,1,n));
    }
    
    
    return 0;
}

1 0
原创粉丝点击