• HDU1698 Just a Hook 线段树 Lazy思想


      该题也算是最基础的线段树了,由于没有很好的理解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;
    }
    

      

  • 相关阅读:
    一步一步学Silverlight 2系列(23):Silverlight与HTML混合之无窗口模式
    一步一步学Silverlight 2系列(25):综合实例之Live Search
    一步一步学Silverlight 2系列(19):如何在Silverlight中与HTML DOM交互(上)
    一步一步学Silverlight 2系列(13):数据与通信之WebRequest
    一步一步学Silverlight 2系列(17):数据与通信之ADO.NET Data Services
    一步一步学Silverlight 2系列(24):与浏览器交互相关辅助方法
    一步一步学Silverlight 2系列(22):在Silverlight中如何用JavaScript调用.NET代码
    一步一步学Silverlight 2系列(27):使用Brush进行填充
    一步一步学Silverlight 2系列(16):数据与通信之JSON
    一步一步学Silverlight 2系列(14):数据与通信之WCF
  • 原文地址:https://www.cnblogs.com/Lyush/p/2139647.html
Copyright © 2020-2023  润新知