zoukankan      html  css  js  c++  java
  • 线段树---成段更新hdu1698 Just a Hook

    hdu1698 Just a Hook
    题意:O(-1)
    思路:O(-1)

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

    题意:给一组棍子染色,不同的颜色有不同的值,执行一系列的区间染色后,问这组棍子的总值是多少。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
     
    #define lson l , m , rt << 1
    #define rson m + 1 , r , rt << 1 | 1
    const int maxn = 111111;
    struct Tree{
     int value;
     int type;
    }tree[maxn<<2];
    int col[maxn<<2];
    
    void PushUp(int rt) {
    	tree[rt].value = tree[rt<<1].value + tree[rt<<1|1].value;
    }
    void PushDown(int rt,int ms) {
    	if (tree[rt].type) {
    		tree[rt<<1].type = tree[rt<<1|1].type = tree[rt].type ;
    		tree[rt<<1].value = (ms - (ms >> 1)) * tree[rt].type;
    		tree[rt<<1|1].value = (ms >> 1) * tree[rt].type;
    		tree[rt].type = 0;
    	}
    }
    void build(int l,int r,int rt) {
    	tree[rt].type=0;
    	tree[rt].value=1;//chushizhi
    	if (l == r) return ;
    	int m = (l + r) >> 1;
    	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) {//标记1  //更新到这就行,不一定更新到最底端
    		tree[rt].type = c;
    		tree[rt].value = c * (r - l + 1);
    		return ;
    	}
    	PushDown(rt , r - l + 1);//延迟标记,这时候后推, (标记2)
    							//比如建了 [1,4]  然后我们第一次的时候是更新[1,2]
    							//		[1,2][3,4]  [1,2]的type就是非0,value往上更新;
    							//	   [1][2][3][4]  第二次如果还是要更新[1,2] 在标记1直接更新
    	int m = (l + r) >> 1;   // 而如果你是要更新[1,1](必定访问到标记2) 那么先进行标记2 让两儿子的value更新 
    	if (L <= m) update(L , R , c , lson); //记得这时候儿子type被赋值,自己type=0;
    	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 , tree[1].value);
    	}
    	return 0;
    }

    我觉得这个讲的也挺不错的:

    // HDU 1698 Just a Hook 线段树(线段替换)插线插线+ 延时标记
    // 延时标记:起一个缓冲的作用,第一次遇到的更新先不更新到底,等下一次更新或者查询的时候再更新到位。
    // 因此线段树结构中的区间和 并不是实际值。
    // 此处的更新到位是指 本次更新或查询所需的最后一层(因为我查的不是点,而是区间),并非到最底层
    // 延时标记下沉的前提:线段树结构中遇到了一个区间完全的包含于待更新区间,即遇到一个待更新区间的子区间
    // 注意的是:
    // 1.下沉这个标记的时候也要更新区间的实际和,下沉过的标记要及时取消
    // 2.递归网上弹准备跳出的时候应该顺便更新区间的实际和,也就是把孩子的两个区间实际和相加
    // 3.往左或者往右需要进行深层递归的条件:该区间的子区间与待更新区间存在交集
    // 4.对我自己要说的,由于是先更新左区间,因此对右区间的更新不受影响,那么待更新的区间就不需要分割了
    // 
    
    /*test data
    1
    10
    4
    1 5 2
    5 9 3
    1 1 1
    10 10 1
    
    	out = 23
    */
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    
    const int M = 400001;
    struct NODE{
    	int value;
    	int left,right; // 其实这两个区间端点都可以不用存起来
    	int buffer;	// 延时标记。
    }node[M];
    
    void BuildTree(int i,int left, int right){
    	node[i].left = left;
    	node[i].right = right;
    	node[i].value = node[i].right - node[i].left + 1;
    	node[i].buffer = 0;
    	if (node[i].left == node[i].right){
    		return ;
    	}
    	BuildTree(i<<1,left,(left+right)/2);
    	BuildTree((i<<1)+1,(left+right)/2+1,right);
    }
    
    int a,b,v; // updata interval = [a,b]
    void UpdataTree(int i){ // only revise the buffer 
    	if (a <= node[i].left && node[i].right <= b){ // if find a  interval contained goal interval completely
    		node[i].value = (node[i].right - node[i].left + 1 ) * v;
    		if (node[i].left != node[i].right) // 末结点不需要延时标记
    		node[i].buffer = v; // replace 
    		return;
    	}
    	if (node[i].buffer){ // if exsit buffer 
    		int l = i << 1;
    		node[l].buffer = node[l+1].buffer = node[i].buffer; // Make buffer sinking
    		node[i].buffer = 0;
    		node[l].value = (node[l].right - node[l].left + 1 ) * node[l].buffer; // 左孩子,利用buffer完成上一次未完成的更新
    		l++;
    		node[l].value = (node[l].right - node[l].left + 1 ) * node[l].buffer;	// 右孩子,利用buffer完成上一次未完成的更新
    	}
    	if (a <= node[i<<1].right) // ***由于先执行的左边,所以待更新区间无需分割,并不影响右边的执行****   ///
    		UpdataTree(i<<1);
    	if (b >= node[(i<<1)+1].left)
    		UpdataTree((i<<1)+1);
    	// finally, this node will be the sum of the two child 
    	node[i].value = node[i<<1].value + node[(i<<1)+1].value;
    }
    
    int main(){
    	freopen("in.txt","r",stdin);
    	int ncase,d=1;
    	scanf("%d",&ncase);
    
    	while(ncase--){
    		int nn,n_u;
    		scanf("%d%d",&nn,&n_u);
    		BuildTree(1,1,nn);
    		while(n_u--){ // updata
    			scanf("%d%d%d",&a,&b,&v);
    			UpdataTree(1); // start from NO.1 interval to updata interval [1,nn] by increase v
    		}
    		printf("Case %d: The total value of the hook is %d.
    ",d++,node[1].value);
    	}
    	return 0;
    }
    


    版权声明:本文为博主原创文章,未经博主允许不得转载。

    today lazy . tomorrow die .
  • 相关阅读:
    华为超大云数据中心落地贵州,这些硬核技术有利支撑“东数西算”
    在高并发环境下该如何构建应用级缓存
    使用 Python Poetry 进行依赖管理
    AI新手语音入门:认识词错率WER与字错率CER
    一文带你了解什么是GitOps
    需求蔓延,常见但不正常,教你如何破
    云图说|初识ModelArts开发者生态社区——AI Gallery
    XML学习笔记:关于字符编码的理解~
    Python中单引号、双引号和三双引号的区别:
    LBFGS算法的使用~
  • 原文地址:https://www.cnblogs.com/france/p/4808774.html
Copyright © 2011-2022 走看看