HDU 1698 Just a Hook 线段树成段更新

算是我真正意义上的区间更新的第一题,我是这样理解区间更新的:

为了节省时间,在更新区间的时候不必每次都更新到叶子节点。如果当前节点的的区间被包含在查询区间内,就暂时只更新这个节点。但是如果仅仅这样,将来在下次更新的时候,如果涉及了该节点的孩子节点,就会出错。

所以有一个办法:在更新的时候,如果我们明确知道了该节点的儿子节点涉及到了将要更新的区间,就事先把它的左右儿子节点按照父节点的val更新了,由于更新是递归实现的,所以如果它的孙子节点也涉及了,孙子节点会在儿子节点的递归层被更新。

这样做肯定比每次都更新到叶子节点大大节省了时间。

AC代码:

/* ***********************************************
Author        :angon
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define REP(i,k,n) for(int i=k;i<n;i++)
#define REPP(i,k,n) for(int i=k;i<=n;i++)
#define scan(d) scanf("%d",&d)
#define scann(n,m) scanf("%d%d",&n,&m)
#define mst(a,k)  memset(a,k,sizeof(a));
#define LL long long
#define maxn 100005
#define mod 100000007
/*
inline int read()
{
    int s=0;
    char ch=getchar();
    for(; ch<'0'||ch>'9'; ch=getchar());
    for(; ch>='0'&&ch<='9'; ch=getchar())s=s*10+ch-'0';
    return s;
}
inline void print(int x)
{
    if(!x)return;
    print(x/10);
    putchar(x%10+'0');
}
*/
int n;
struct node
{
    int l,r,v,sum; //v 代表类型,sum代表总和
}seg[maxn*4];

void build(int i,int l,int r)
{
    seg[i].l=l;
    seg[i].r=r;
    seg[i].v=1;
    if(l==r)
    {
        seg[i].sum=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    seg[i].sum=seg[i<<1].sum+seg[i<<1|1].sum;

}

void update(int i,int l,int r,int val)
{
    if(seg[i].v==val) return ; //剪枝
    if(l<=seg[i].l && r>=seg[i].r)
    {
        seg[i].v=val;
        seg[i].sum=(seg[i].r-seg[i].l+1)*val;
        return ;
    }
    if(seg[i].v>0)    //如果大于0,说明区间里面颜色一样
    {               //由上面一个if没有return可知后面必定对子树进行操作,
        seg[i<<1].v=seg[i<<1|1].v=seg[i].v;    //所以先更新孩子节点
        seg[i<<1].sum=(seg[i<<1].r-seg[i<<1].l+1)*seg[i].v;
        seg[i<<1|1].sum=(seg[i<<1|1].r-seg[i<<1|1].l+1)*seg[i].v;
        seg[i].v=0;
    }
    int mid=(seg[i].l+seg[i].r)>>1;
    if(l<=mid) update(i<<1,l,r,val);
    if(r>mid) update(i<<1|1,l,r,val);
    seg[i].sum=seg[i<<1].sum+seg[i<<1|1].sum;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t,q,x,y,c;
    scan(t);
    int cas=1;
    while(t--)
    {
        scan(n);
        build(1,1,n);

        scan(q);
        while(q--)
        {
            scanf("%d%d%d",&x,&y,&c);
            update(1,x,y,c);
        }
        printf("Case %d: The total value of the hook is %d.\n",cas++,seg[1].sum);
    }
    return 0;
}

附kuangbin大神的代码,更加符合标准,更模版化,再看一遍也许可以帮助理解

/*
HDU 1689
线段树
成段更新
*/


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int MAXN=100010;
struct Node
{
    int l,r;
    int lazy,tag;
    int sum;
}segTree[MAXN*3];
void Build(int i,int l,int r)
{
    segTree[i].l=l;
    segTree[i].r=r;
    segTree[i].lazy=0;
    segTree[i].tag=0;
    if(l==r)
    {
        segTree[i].sum=1;
        return;
    }
    int mid=(l+r)>>1;
    Build(i<<1,l,mid);
    Build((i<<1)|1,mid+1,r);
    segTree[i].sum=segTree[i<<1].sum+segTree[(i<<1)|1].sum;
}
void update(int i,int l,int r,int v)
{
    if(segTree[i].l==l&&segTree[i].r==r)//成段更新
    {
        segTree[i].lazy=1;
        segTree[i].tag=v;
        segTree[i].sum=(r-l+1)*v;
        return;
    }
    int mid=(segTree[i].l+segTree[i].r)>>1;
    if(segTree[i].lazy==1)
    {
        segTree[i].lazy=0;
        update(i<<1,segTree[i].l,mid,segTree[i].tag);
        update((i<<1)|1,mid+1,segTree[i].r,segTree[i].tag);
        segTree[i].tag=0;
    }
    if(r<=mid) update(i<<1,l,r,v);
    else if(l>mid)update((i<<1)|1,l,r,v);
    else
    {
        update(i<<1,l,mid,v);
        update((i<<1)|1,mid+1,r,v);
    }
    segTree[i].sum=segTree[i<<1].sum+segTree[(i<<1)|1].sum;
}
int main()
{
      //  freopen("in.txt","r",stdin);
 //  freopen("out.txt","w",stdout);
    int x,y,z;
    int n;
    int m;
    int T;
    scanf("%d",&T);
    int iCase=0;
    while(T--)
    {
        iCase++;
        scanf("%d%d",&n,&m);
        Build(1,1,n);
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&z);
            update(1,x,y,z);
        }
        printf("Case %d: The total value of the hook is %d.\n",iCase,segTree[1].sum);
    }
    return 0;
}


你可能感兴趣的:(HDU 1698 Just a Hook 线段树成段更新)