该题也算是最基础的线段树了,由于没有很好的理解Lazy思想,导致前面为了写出一个正确的程序花了半天功夫啊。前面是这样想的,对于某一段区间,如果已经赋了值,那么后面的修改就在这个值上进行,例如前面如果1 - 3 赋为2,后面如果又有一次 2 - 3赋为1的话,那么就在 2- 3的区间上赋值为 -1,因为前面已经在1-3算作 2 了。虽说思路出来了,但后面一直还是WA,原因在于经过多次的更新后,有些应该被舍弃的值被重复利用了,比如上例中再出现一组1 - 3 赋值为3,后面的 2- 3区间值就不对了,于是又加了时间戳,最后写出来AC的代码也便是搓不可言了。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> using namespace std; int N; struct Node { int l, r, val, ti; Node *lch, *rch; Node( int left, int right ) { l= left, r= right, val= 0, ti= 0; lch= rch= NULL; } int getmid( ) { return ( l+ r )/ 2; } }; void creat( Node *p ) { if( p->r- p->l> 1 ) // 如果该区间可以再细分 { p->lch= new Node( p->l, p->getmid() ); // 左孩子为 l 到 mid p->rch= new Node( p->getmid(), p->r ); // 右孩子为 mid 到 r creat( p->lch ), creat( p->rch ); // 递归构建子区间 } } void update( Node *p, int l, int r, int add, int tt, int ti ) { if( p->l== l&& p->r== r ) // 如果找到了一个能够来求和的区间 { p->val= add; // 其lazy值加上计算出来的增量 p->ti= ti; // 对于区间更新的节点加上时间戳 return; // 及时结束该次递归过程 } if( p->ti> tt ) // 如果该点是后更新的,才减去重复计算的部分 { add-= p->val; tt= p->ti; } if( l>= p->getmid() ) // 如果区间在该节点的右枝 { update( p->rch, l, r, add, tt, ti ); } else if( r<= p->getmid() ) // 如果区间在该节点的左枝 { update( p->lch, l, r, add, tt, ti ); } else // 如果区间横跨两个孩子所表示的区间 { update( p->lch, l, p->getmid(), add, tt, ti ); update( p->rch, p->getmid(), r, add, tt, ti ); } } void sum( Node *p, int ti, int &ans ) // 最重要的求和过程 { if( !p ) { return; } if( p->ti> ti ) { ans+= ( p->r- p->l )* p->val; sum( p->lch, p->ti, ans ); sum( p->rch, p->ti, ans ); } else { sum( p->lch, ti, ans ); sum( p->rch, ti, ans ); } } void _free( Node *p ) { if( p->lch ) { _free( p->lch ); } if( p->rch ) { _free( p->rch ); } free( p ); } int main() { int T, ti, ans; scanf( "%d", &T ); for( int t= 1; t<= T; ++t ) { ans= 0; scanf( "%d", &N ); Node *r= new Node( 1, N+ 1 ); creat( r ); update( r, 1, N+ 1, 1, 0, 1 ); // 把第一次更新看作是初始化 scanf( "%d", &ti ); for( int i= 1; i<= ti; ++i ) { int tl, tr, tadd; scanf( "%d %d %d", &tl, &tr, &tadd ); update( r, tl, tr+ 1, tadd, 0, i+ 1 ); } sum( r, -1, ans ); printf( "Case %d: The total value of the hook is %d.\n", t, ans ); _free( r ); // 释放所有节点 } return 0; }
还好,重新理解了Lazy思想后,过这题就很简单了。
代码如下:
#include <cstdio> #include <cstdlib> #include <cmath> using namespace std; int N; struct Node { int l ,r, val; Node *lch, *rch; Node ( int ll, int rr ) { l= ll, r= rr, val= -1; lch= rch= NULL; } int Gm( ) { return ( l+ r )>> 1; } }; void Creat( Node *p ) { if( p->r- p->l> 1 ) { p->lch= new Node( p->l, p->Gm() ); p->rch= new Node( p->Gm(), p->r ); Creat( p->lch ), Creat( p->rch ); } } void Update( Node *p, int l, int r, int val ) { if( p->val== val ) { return; } if( p->l== l&& p->r== r ) { p->val= val; return; } if( p->val!= -1 ) { p->lch->val= p->val, p->rch->val= p->val; p->val= -1; // 将该节点赋为杂色 } if( l>= p->Gm() ) { Update( p->rch, l, r, val ); } else if( r<= p->Gm() ) { Update( p->lch, l, r, val ); } else { Update( p->lch, l, p->Gm(), val ); Update( p->rch, p->Gm(), r, val ); } } int Sum( Node *p ) { if( !p ) { return 0; } if( p->val!= -1 ) { return ( p->r- p->l )* p->val; } else { return Sum( p->lch )+ Sum( p->rch ); } } void _free( Node *p ) { if( p->lch ) { _free( p->lch ); } if( p->rch ) { _free( p->rch ); } free( p ); } int main( ) { int T; scanf( "%d", &T ); for( int t= 1; t<= T; ++t ) { int op; scanf( "%d", &N ); Node *r= new Node( 1, N+ 1 ); Creat( r ); scanf( "%d", &op ); Update( r, 1, N+ 1, 1 ); for( int i= 1; i<= op; ++i ) { int ll, rr, val; scanf( "%d %d %d", &ll, &rr, &val ); Update( r, ll, rr+ 1, val ); } printf( "Case %d: The total value of the hook is %d.\n", t, Sum( r ) ); _free( r ); } }
网络上更高效的解法。
#include <iostream> #include <cstdio> using namespace std; int data[100005][3]; int main() { int t,q,n,i,j,sum,k,v; scanf("%d",&t); for(i=1;i<=t;i++) { scanf("%d%d",&n,&q); for(j=1;j<=q;j++) scanf("%d%d%d",&data[j][0],&data[j][1],&data[j][2]); sum=0; for(k=1;k<=n;k++) { v=1; for(j=q;j>=1;j--) if(data[j][0]<=k && k<=data[j][1])//寻找k所在的更新区间,若存在则更新,不存在v=1不变 { v=data[j][2]; //若找的最后面的更新区间,则停止,因为前面的会被覆盖 break; } sum+=v; } printf("Case %d: The total value of the hook is %d.\n",i,sum); } return 0; }