算是我真正意义上的区间更新的第一题,我是这样理解区间更新的:
为了节省时间,在更新区间的时候不必每次都更新到叶子节点。如果当前节点的的区间被包含在查询区间内,就暂时只更新这个节点。但是如果仅仅这样,将来在下次更新的时候,如果涉及了该节点的孩子节点,就会出错。
所以有一个办法:在更新的时候,如果我们明确知道了该节点的儿子节点涉及到了将要更新的区间,就事先把它的左右儿子节点按照父节点的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;
}