ACM-线段树

http://blog.csdn.net/libin56842/article/details/8530197

基础可以看上面这篇文章

风格:

maxn是题目给的最大区间,而节点数要开4倍,确切的说……

lson和rson辨别表示结点的左孩子和右孩子。

PushUp(int rt)是把当前结点的信息更新到父节点

PushDown(int rt)是把当前结点的信息更新给孩子结点。

rt表示当前子树的根(root),也就是当前所在的结点。

思想:

对于每个非叶节点所标示的结点 [a,b],其做孩子表示的区间是[a,(a+b)/2],其右孩子表示[(a+b)/2,b].

构造:

离散化和线段树:

题目:x轴上有若干个线段,求线段覆盖的总长度。

普通解法:设置坐标范围[min,max],初始化为0,然后每一段分别染色为1,最后统计1的个数,适用于线段数目少,区间范围小。

离散化的解法:离散化就是一一映射的关系,即将一个大坐标和小坐标进行一一映射,适用于线段数目少,区间范围大。

例如:[10000,22000],[30300,55000],[44000,60000],[55000,60000].

第一步:排序 10000 22000 30300 44000 55000 60000

第二部:编号 1        2        3         4       5         6

第三部:用编号来代替原数,即小数代大数 。

[10000,22000]~[1,2]

[30300,55000]~[3,5]

[44000,60000]~[4,6]

[55000,60000]~[5,6]

然后再用小数进行普通解法的步骤,最后代换回去。

线段树的解法:线段树通过建立线段,将原来染色O(n)的复杂度减小到 log(n),适用于线段数目多,区间范围小的情况。

离散化的线段树:适用于线段数目多,区间范围大的情况。

构造:

动态数据结构:

struct node{

node* left;

node* right;

……

}

静态全局数组模拟(完全二叉树):

struct node{

int left;

int right;

……

}Tree[MAXN]

http://www.xuebuyuan.com/1470670.html

线段树主要用四种用法

单点更新:

模板:

struct node
{
    int l,r,c;
}T[MAXN*4];

void PushUp(int rt)
{
    T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;
}

void build(int l,int r,int x)
{
    T[x].l = l;
    T[x].r = r;
    T[x].c = 0;
    if (l == r) return;
    int mid = (l+r)>>1;
    build(l,mid,x<<1);
    build(mid+1,r,(x<<1) + 1);
}

void update(int val,int l,int x)
{
    if(T[x].l == T[x].r && T[x].l == l)
    {
        T[x].c += val;
        return;
    }
    int mid = (T[x].l + T[x].r)>>1;
    if (l > mid)
    {
        update(val,l,(x<<1) + 1);
    }
    else
    {
        update(val,l,x<<1);
    }
    PushUp(x);
}

int n,m,ans;

void query(int l,int r,int x)
{
    if(T[x].l == l && T[x].r == r)
    {
        ans += T[x].c;
        return;
    }
    int mid = (T[x].l + T[x].r)>>1;
    if (l > mid)
    {
        query(l,r,(x<<1)+1);
    }
    else if(r<=mid)
    {
        query(l,r,(x<<1));
    }
    else
    {
        query(l,mid,(x<<1));
        query(mid+1,r,(x<<1)+1);
    }
}

HDU 1166

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <queue>
#include <cctype>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <sstream>
using namespace std;

#define mem(a,b) memset(a,b,sizeof(a))
#define pf printf
#define sf scanf
#define spf sprintf
#define pb push_back
#define debug printf("!\n")
#define MAXN 55555
#define MAX(a,b) a>b?a:b
#define blank pf("\n")
#define LL long long
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define pqueue priority_queue
#define INF 0x3f3f3f3f

struct node
{
    int l,r,c;
}T[MAXN*4];

void PushUp(int rt)
{
    T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;
}

void build(int l,int r,int x)
{
    T[x].l = l;
    T[x].r = r;
    T[x].c = 0;
    if (l == r) return;
    int mid = (l+r)>>1;
    build(l,mid,x<<1);
    build(mid+1,r,(x<<1) + 1);
}

void update(int val,int l,int x)
{
    if(T[x].l == T[x].r && T[x].l == l)
    {
        T[x].c += val;
        return;
    }
    int mid = (T[x].l + T[x].r)>>1;
    if (l > mid)
    {
        update(val,l,(x<<1) + 1);
    }
    else
    {
        update(val,l,x<<1);
    }
    PushUp(x);
}

int n,m,ans;

void query(int l,int r,int x)
{
    if(T[x].l == l && T[x].r == r)
    {
        ans += T[x].c;
        return;
    }
    int mid = (T[x].l + T[x].r)>>1;
    if (l > mid)
    {
        query(l,r,(x<<1)+1);
    }
    else if(r<=mid)
    {
        query(l,r,(x<<1));
    }
    else
    {
        query(l,mid,(x<<1));
        query(mid+1,r,(x<<1)+1);
    }
}

int main()
{
    int t,i,kase=1;
    char d[10];
    sf("%d",&t);
    while(t--)
    {
        mem(T,0);
        pf("Case %d:\n",kase++);
        sf("%d",&n);
        build(1,n,1);
        for(i=1;i<=n;i++)
        {
            int tmp;
            sf("%d",&tmp);
            update(tmp,i,1);
        }

        while (sf("%s",d) != EOF)
        {
            if (d[0] == ‘E‘) break;
            int x, y;
            sf("%d%d", &x, &y);
            if (d[0] == ‘Q‘)
            {
                ans = 0;
                query(x,y,1);
                pf("%d\n",ans);
            }
            if (d[0] == ‘S‘) update(-y,x,1);
            if (d[0] == ‘A‘) update(y,x,1);
        }
    }
    return 0;
}
时间: 2024-10-22 21:48:32

ACM-线段树的相关文章

[ACM] 线段树模板

#include<iostream> #include<cmath> using namespace std; #define maxn 200005 class Node{ public: int l,r; int add;//附加值 int sum; }node[maxn]; int getRight(int n){//获得满足2^x>=n的最小x[从0层开始,给编号获得层数] return ceil(log10(n*1.0)/log10(2.0)); } void bu

ACM: Billboard 解题报告-线段树

Billboard Time Limit:8000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description 在学校的入口处有一个巨大的矩形广告牌,高为h,宽为w.所有种类的广告都可以贴,比如ACM的广告啊,还有餐厅新出了哪些好吃的,等等.. 在9月1号这天,广告牌是空的,之后广告会被一条一条的依次贴上去. 每张广告都是高度为1宽度为wi的细长的矩形纸条. 贴广告的人总是会优先选择最上面的位置来帖,而且在所有

【线段树】HDU 5493 Queue (2015 ACM/ICPC Asia Regional Hefei Online)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5493 题目大意: N个人,每个人有一个唯一的高度h,还有一个排名r,表示它前面或后面比它高的人的个数,求按身高字典序最小同时满足排名的身高排列. 题目思路: [线段树] 首先可以知道,一个人前面或后面有r个人比他高,那么他是第r+1高或第n-i-r+1高,i为这个人是第几高的. 所以先将人按照身高从小到大排序,接下来,把当前这个人放在第k=min(r+1,n-i-r+1)高的位置. 用线段树维护包

ACM学习历程—HDU 5023 A Corrupt Mayor&#39;s Performance Art(广州赛区网赛)(线段树)

Problem Description Corrupt governors always find ways to get dirty money. Paint something, then sell the worthless painting at a high price to someone who wants to bribe him/her on an auction, this seemed a safe way for mayor X to make money. Becaus

北大ACM暑期培训(1)——线段树,树状数组

本文出自:http://blog.csdn.net/svitter 今天ACM暑期实训开始了,今天讲述的内容是: 7.14  数据结构(一): 线段树,树状数组,二维线段树. 线段树:invertal tree (称为区间树更加合适) 作用:快速区间查询,用于解决区间统计的有关问题. 重点:同层节点不重叠. 每层最多有两个终止节点. 更新和进行区间分解的时间复杂度均为log(n); 方法:调用会多次使用递归更新插入查询: 空间:开空间的时候,一般情况下开4n大小,2*2log[n] - 1 <=

[ACM] SCU 1555 Inversion Sequence (线段树)

http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1555 输入5个数 1 2 0 1 0 表示1前面有1个比它大的数,2前面有2个比它大的数-.. 求一个1~n的排列,比如这个就输出3 1 5 2 4 1前面有1个比它大的数,那么1肯定在第二位 2前面有2个比它大的数,那么2肯定排在第四位,有一位被1占了. 3前面有0个比它大的数,那么3肯定在第一位 维护线段树,叶子结点的值为1,维护和.从左到右找第多少个1就可以了. 比如1前面有1个比它大的数

hdu acm 1166 敌兵布阵 (线段树)

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 37903    Accepted Submission(s): 15985 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

《ACM/ICPC 算法训练教程》读书笔记 之 数据结构(线段树详解)

依然延续第一篇读书笔记,这一篇是基于<ACM/ICPC 算法训练教程>上关于线段树的讲解的总结和修改(这本书在线段树这里Error非常多),但是总体来说这本书关于具体算法的讲解和案例都是不错的. 线段树简介 这是一种二叉搜索树,类似于区间树,是一种描述线段的树形数据结构,也是ACMer必学的一种数据结构,主要用于查询对一段数据的处理和存储查询,对时间度的优化也是较为明显的,优化后的时间复杂为O(logN).此外,线段树还可以拓展为点树,ZWK线段树等等,与此类似的还有树状数组等等. 例如:要将

[ACM] Color the ball [线段树水题][数组开大]

Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色.但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗? Input 每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N).  当N

ACM学习历程—HDU5696 区间的价值(分治 &amp;&amp; RMQ &amp;&amp; 线段树 &amp;&amp; 动态规划)

http://acm.hdu.edu.cn/showproblem.php?pid=5696 这是这次百度之星初赛2B的第一题,但是由于正好打省赛,于是便错过了.加上2A的时候差了一题,当时有思路,但是代码就是过不去..这次应该是无缘复赛了.. 先不水了,省赛回来,我看了一下这个题,当时有个类似于快排的想法,今天试了一下,勉强AC了..跑了3S多. 思路就是我枚举区间左值lt,那么[lt, n]区间内最值的角标分别为mi和ma.于是设to = max(mi, ma).也就是说在to右侧的所有区间