zoukankan      html  css  js  c++  java
  • 线段树之成段更新( 需要用到延迟标记,简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候)

    HDU  1698

    链接:  http://acm.hdu.edu.cn/showproblem.php?pid=1698

    线段树功能:update:成段替换 (由于只query一次总区间,所以可以直接输出1结点的信息)

    <span style="font-size:18px;">#include<iostream>
    #include<cstdio>
    #include<cstring>
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    using namespace std;
    const int maxn=100001;
    int sum[maxn<<2];
    int col[maxn<<2];
    void pushUP(int rt)       //当前节点信息更新给父节点 
    {
    	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void pushdown(int rt,int m)     //当前节点信息更新给儿子节点 
    {
    	if(col[rt])
    	{
    		col[rt<<1]=col[rt<<1|1]=col[rt];
    		sum[rt<<1]=(m-(m>>1))*col[rt];
    		sum[rt<<1|1]=(m>>1)*col[rt];
    		col[rt]=0;
    	}
    }
    void build(int l,int r,int rt)   //建立线段树 
    {
    	col[rt]=0;
    	sum[rt]=1;
    	if(l==r)
    	return;
    	int m=(l+r)/2;
    	build(lson);
    	build(rson);
    	pushUP(rt);
    }
    void update(int L,int R,int c,int l,int r,int rt)   //成段替换,由于只query一次总区间,所以可以直接输出1节点的信息 
    {
    	if(L<=l&&r<=R)
    	{
    		col[rt]=c;
    		sum[rt]=(r-l+1)*c;
    		return;
    	}
    	pushdown(rt,r-l+1);
    	int m=(l+r)/2;
    	if(L<=m)   update(L,R,c,lson);
    	if(R>m)   update(L,R,c,rson);
    	pushUP(rt);
    }
    int main()
    {
    	int T,n,m;
    	scanf("%d",&T);
    	for(int cas=1;cas<=T;cas++)
    	{
    		scanf("%d%d",&n,&m);
    		build(1,n,1);;
    		while(m--)
    		{
    			int a,b,c;
    			scanf("%d%d%d",&a,&b,&c);
    			update(a,b,c,1,n,1);
    		}
    		printf("Case %d: The total value of the hook is %d.
    ",cas , sum[1]);
    	}	
    	return 0;
    }</span>

    poj 3468

    链接:http://poj.org/problem?id=3468

    题解:很好的一个区间更新的线段树的模型,线段树的功能,update成段增减,query区间求和,关键在于对pushdown的理解,当扩展区间与节点上区间完全吻合时,停止向下

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    using namespace std;
    const int maxn=100001;
    long long  sum[maxn<<2],col[maxn<<2];
    void pushUP(int rt)
    {
    	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void pushdown(int rt,int m)
    {
    	if(col[rt])
    	{
    		col[rt<<1]+=col[rt];
    		col[rt<<1|1]+=col[rt];
    		sum[rt<<1]+=(m-(m>>1))*col[rt];
    		sum[rt<<1|1]+=(m>>1)*col[rt];
    		col[rt]=0;
    	}
    }
    void build(int l,int r,int rt)
    {
    	col[rt]=0;
    	if(l==r)
    	{
    		scanf("%lld",&sum[rt]);
    		return;
    	}
    	int m=(l+r)/2;
    	build(lson);
    	build(rson);
    	pushUP(rt);
    }
    void update(int L,int R,int c,int l,int r,int rt)   //成段增减 
    {
    	if(L<=l&&r<=R)
    	{
    		col[rt]+=c;
    		sum[rt]+=c*(r-l+1);
    		return;
    	}
    	pushdown(rt,r-l+1);
    	int m=(l+r)/2;
    	if(L<=m)   update(L,R,c,lson);
    	if(R>m)    update(L,R,c,rson);
    	pushUP(rt);
    }
    long long query(int L,int R,int l,int r,int rt)     //区间求和 
    {
    	if(L<=l&&r<=R)
    	return sum[rt];
    	pushdown(rt,r-l+1);
    	long long ret=0;
    	int m=(l+r)/2;
    	if(L<=m)   ret+=query(L,R,lson);
    	if(R>m)    ret+=query(L,R,rson);
    	return ret;
    }
    int main()
    {
    	int n,q;
    	scanf("%d%d",&n,&q);
    	build(1,n,1);
    	while(q--)
    	{
    		int a,b,c;
    		char op[2];
    		scanf("%s",op);
    		if(op[0]=='Q')
    		{
    			scanf("%d%d",&a,&b);
    			printf("%lld
    ",query(a,b,1,n,1));
    		}
    		else
    		{
    			scanf("%d%d%d",&a,&b,&c);
    			update(a,b,c,1,n,1);
    		}
    	}
    	return 0;
    }

    poj2528(线段树+离散化)

    题目链接:http://poj.org/problem?id=2528

    题目解答:

    离散化就是压缩区间,使原有的长区间映射到新的短区间,但是区间压缩前后的覆盖关系不变。举个例子:
    有一条1到10的数轴(长度为9),给定4个区间[2,4] [3,6] [8,10] [6,9],覆盖关系就是后者覆盖前者,每个区间染色依次为 1 2 3 4。
    现在我们抽取这4个区间的8个端点,2 4 3 6 8 10 6 9
    然后删除相同的端点,这里相同的端点为6,则剩下2 4 3 6 8 10 9
    对其升序排序,得2 3 4 6 8 9 10
    然后建立映射
    2     3     4     6     8     9   10
    ↓     ↓      ↓     ↓     ↓     ↓     ↓
    1     2     3     4     5     6     7
    那么新的4个区间为 [1,3] [2,4] [5,7] [4,6],覆盖关系没有被改变。新数轴为1到7,即原数轴的长度从9压缩到6,显然构造[1,7]的线段树比构造[1,10]的线段树更省空间,搜索也更快,但是求解的结果却是一致的。
    离散化时有一点必须要注意的,就是必须先剔除相同端点后再排序,这样可以减少参与排序元素的个数,节省时间。

    由于此题数据较大,所以此题要用离散化

    线段树功能:update:成段替换 query:简单hash

    #include<iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define lson l , m , rt << 1
    #define rson m + 1 , r , rt << 1 | 1
    const int maxn = 11111;
    bool hash[maxn];
    int li[maxn] , ri[maxn];
    int X[maxn*3];
    int col[maxn<<4];
    int cnt;
    void PushDown(int rt)           //更新到儿子节点(此处为覆盖,所以用这种方法更新)
    {
    	if (col[rt] != -1)
        {
    		col[rt<<1] = col[rt<<1|1] = col[rt];
    		col[rt] = -1;
    	}
    }
    void update(int L,int R,int c,int l,int r,int rt)      //成段替换
    {
    	if (L <= l && r <= R) {
    		col[rt] = c;
    		return ;
    	}
    	PushDown(rt);
    	int m = (l + r) >> 1;
    	if (L <= m) update(L , R , c , lson);
    	if (m < R) update(L , R , c , rson);
    }
    void query(int l,int r,int rt)     //简单的hash,cnt统计离散化以后的长度
    {
    	if (col[rt] != -1)
        {
    		if (!hash[col[rt]]) cnt ++;
    		hash[ col[rt] ] = true;
    		return ;
    	}
    	if (l == r) return ;
    	int m = (l + r) >> 1;
    	query(lson);
    	query(rson);
    }
    int Bin(int key,int n,int X[])       //二分查找的过程
    {
    	int l = 0 , r = n - 1;
    	while (l <= r)
        {
    		int m = (l + r) >> 1;
    		if (X[m] == key) return m;
    		if (X[m] < key) l = m + 1;
    		else r = m - 1;
    	}
    	return -1;
    }
    int main()
    {
    	int T , n;
    	scanf("%d",&T);
    	while (T --)
        {
    		scanf("%d",&n);
    		int nn = 0;
    		for (int i = 0 ; i < n ; i ++)   //离散化的过程  
    		{
    			scanf("%d%d",&li[i] , &ri[i]);
    			X[nn++] = li[i];
    			X[nn++] = ri[i];
    		}
    		sort(X , X + nn);
    		int m = 1;
    		for (int i = 1 ; i < nn; i ++)
    		{
    			if (X[i] != X[i-1]) X[m ++] = X[i];
    		}
    		for (int i = m - 1 ; i > 0 ; i --)
    		{
    			if (X[i] != X[i-1] + 1) X[m ++] = X[i-1] + 1;
    		}
    		sort(X , X + m);
    		memset(col , -1 , sizeof(col));
    		for (int i = 0 ; i < n ; i ++)
    		{
    			int l = Bin(li[i], m, X);
    			int r = Bin(ri[i], m, X);
    			update(l, r, i, 0, m - 1, 1);
    		}
    		cnt = 0;
    		memset(hash, false, sizeof(hash));
    		query(0, m - 1, 1);
    		printf("%d
    ",cnt);
    	}
    	return 0;
    }
    


  • 相关阅读:
    Lua 学习之基础篇一<Lua 运算符>
    Git: invalid active developer path
    Lua中使用continue 小练习
    Xcode 运行objc_msgSend 提示objc_msgsend()Too many arguments to function call, expected 0
    逆向思维
    机场
    旅行者
    好图计数
    支配树
    一般图最大匹配
  • 原文地址:https://www.cnblogs.com/wolf940509/p/6617127.html
Copyright © 2011-2022 走看看