poj 2777(线段树的节点更新策略)

/*
之前的思想是用回溯的方式进行颜色的更新的!如果用回溯的方法的话,就是将每一个节点的颜色都要更新
通过子节点的颜色情况来判断父节点的颜色情况 !这就是TLE的原因!

后来想一想没有必要 !加入[a, b] 区间有p管辖,那么tree[p]的颜色值就是[a, b]所有点的颜色值!
如果[a,b]的子区间[c,d]没被跟新,那么tree[p]也是[c,d]的值!
否则,在更新[c,d]区间的时候,一定会经过 p 点!然后由上到下更新p<<1 和 p<<1|1 的值!
当找到[c,d]区间所对应的p‘时,并更新p’的值!、

之前的剪枝是点返回, 后面的是线段返回,当然更快!
*/
#include<string>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define M 100005
using namespace std;

int tree[4*M];

int color[32];
int L, T, O;

void buildT(int ld, int rd, int p){
    if(ld<=rd){
        tree[p]=1;
        if(ld==rd)
           return ;
         int mid = (ld+rd)/2;
         buildT(ld, mid, p<<1);
         buildT(mid+1, rd, p<<1|1);
    }
}

void updateT(int ld, int rd, int a, int b, int p, int k){
    if(tree[p] == k) return ;//如果当前更新的颜色和 之前p所管辖的区间的颜色相同,则返回 

    if(ld==a && rd==b){//p所管辖的区间的点的颜色全部是k!如果其子区间的颜色被更改,那么
        tree[p]=k;     //在更新子区间的时候一定会经过 p点,让后通过p更新 p<<1 和 p<<1|1 子区间的颜色!
        return ;
    }

    if(tree[p]!=-1){//也就是在经过父节点时更新子节点的颜色状态,也就是[a,b]包含在 p点所管辖的区间内
       tree[p<<1] = tree[p<<1|1] = tree[p];
       tree[p]=-1;
    }
    if(ld<rd){
       int mid = (ld+rd)/2;
       if(mid<a)
         updateT(mid+1, rd, a, b, p<<1|1, k);
       else if(mid>=b)
         updateT(ld, mid, a, b, p<<1, k);
       else{
          updateT(ld, mid, a, mid, p<<1, k);
          updateT(mid+1, rd, mid+1, b, p<<1|1, k);
       }
    }
}

void queryT(int ld, int rd, int a, int b, int p){
   if(ld>rd) return ;
   if(tree[p]!=-1){
         color[tree[p]]=1;
   }
   else{
       int mid = (ld+rd)/2;
       if(mid<a)
         queryT(mid+1, rd, a, b, p<<1|1);
       else if(mid>=b)
         queryT(ld, mid, a, b, p<<1);
       else{
          queryT(ld, mid, a, mid, p<<1);
          queryT(mid+1, rd, mid+1, b, p<<1|1);
       }
   }
}

int main(){

   while(scanf("%d%d%d", &L, &T, &O)!=EOF){
      buildT(1, L, 1);
      while(O--){
         char ch[2];
         int a, b, c;
         scanf("%s", ch);
         if(ch[0]=='C'){
             scanf("%d%d%d", &a, &b, &c);
             if(a>b){
               a^=b;
               b^=a;
               a^=b;
            }
             updateT(1, L, a, b, 1, c);
         }
         else{
            scanf("%d%d", &a, &b);
            if(a>b){
               a^=b;
               b^=a;
               a^=b;
            }
            memset(color, 0, sizeof(color));
            queryT(1, L, a, b, 1);
            int cnt=0;
            for(int i=1; i<=T; ++i)
               if(color[i]) ++cnt;
            printf("%d\n", cnt);
         }
      }
   }
   return 0;
}
时间: 2024-10-29 07:34:49

poj 2777(线段树的节点更新策略)的相关文章

HDU 1698 线段树成段更新

题意:线段树成段更新,最后查询全区间. #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 100005 int node[maxn<<2],col[maxn<<2]; void build(int rt,int l,int r) { col[rt]=0,node[rt]

POJ 3468 线段树 区间更新区间查询

题意:给出一段数列,任意区间加上一个整数v,任意区间查询.给出N个数,Q次操作. 线段树的题,延迟指针不更新到底就行了. #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 100005 long long sum[maxn<<2],col[maxn<<2]; void

【转】POJ 3264 线段树解法

每个算法都是数学家或者计算机学家多年研究的结果,不是我自己臆造的,所以学习一个新算法的最佳方法还是看写的好的代码. 按照惯例,我就粘贴一个网上写的很好的帖子... 原文地址:http://ip96cns.blog.163.com/blog/static/17009519220112525029459/ 线段树的查找:(感谢高手指点,虽然只是一点却让我把线段树的内容理顺了)这里是我的一些总结吧           一个线段树的结点表示一个区间,同时结点中保存所需要的信息.          如果询

《程序设计解题策略》——1.3 利用线段树解决区间计算问题

1.3 利用线段树解决区间计算问题 在现实生活中,我们经常遇到与区间有关的问题,例如,记录一个区间的最值(最大或最小值)和总量,并在区间的插入.删除.修改中维护这些最值和总量:再如,统计若干矩形并的面积.线段树拥有良好的树形二分特征,我们可以从其定义和结构中发现,在线段树的基础上完成这些问题的计算操作,是十分简捷和高效的.1.3.1 线段树的基本概念 一棵二叉树,记为T(a,b),参数a.b表示该节点表示区间[a,b].区间的长度b-a记为L.递归定义T[a,b]: 若区间长度L>1:区间[a,

线段树(Segment Tree)

1.概述 线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即"子数组"),因而常用于解决数列维护问题,基本能保证每个操作的复杂度为O(lgN). 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b].因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度. 使用线段树可以

[算法系列之二十三]线段树(Interval Tree)

一 背景 在信息学竞赛中,我们经常会碰到一些跟区间有关的问题,比如给一些区 间线段求并区间的长度,或者并区间的个数等等.这些问题的描述都非常简单,但是通常情况下数据范围会非常大,而朴素方法的时间复杂度过高,导致不能在规定时间内得到问题的解.这时,我们需要一种高效的数据结构来处理这样的问题,在本文中,我们介绍一种基于分治思想的数据结构--线段树. 二 简介 线段树是一种二叉树形结构,属于平衡树的一种.它将线段区间组织成树形的结构,并用每个节点来表示一条线段.一棵[1,10)的线段树的结构如图1.1

经典算法题每日演练——第十二题 线段树

       这一篇我们来看树状数组的加强版线段树,树状数组能玩的线段树一样可以玩,而且能玩的更好,他们在区间求和,最大,平均 等经典的RMQ问题上有着对数时间的优越表现. 一:线段树      线段树又称"区间树",在每个节点上保存一个区间,当然区间的划分采用折半的思想,叶子节点只保存一个值,也叫单元节点,所 以最终的构造就是一个平衡的二叉树,拥有CURD的O(lgN)的时间. 从图中我们可以清楚的看到[0-10]被划分成线段的在树中的分布情况,针对区间[0-N],最多有2N个节点,

poj 1171 Picture 线段树

     经典的线段树问题,看了好久才看懂      解法很简单,按y坐标从小到大,依次扫描每条线段,每次利用线段树记录当前图形在x轴上的投影,然后用这次投影减去上次就是x轴上变化量,而y轴,因为按y轴枚举,只需要用y的差值乘以2再乘以当前线段数即可.      而线段树的处理就是遇到下边是加入线段树,遇到上边删去及记录当前投影长度,及投影分段情况      看到网上还有种括号匹配的方法,离散化后枚举,复杂度n^2 /* author:jxy lang:C/C++ university:Chin

poj 2528 Mayor&#039;s posters(线段树+离散化)

/* poj 2528 Mayor's posters 线段树 + 离散化 离散化的理解: 给你一系列的正整数, 例如 1, 4 , 100, 1000000000, 如果利用线段树求解的话,很明显 会导致内存的耗尽.所以我们做一个映射关系,将范围很大的数据映射到范围很小的数据上 1---->1 4----->2 100----->3 1000000000----->4 这样就会减少内存一些不必要的消耗 建立好映射关系了,接着就是利用线段树求解 */ #include<ios