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