回档|校门外的树3|线段树的应用

描述

校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
K=1,读入l,r表示在l~r之间种上的一种树
K=2,读入l,r表示询问l~r之间能见到多少种树
(l,r>0)
输入格式
第一行n,m表示道路总长为n,共有m个操作
接下来m行为m个操作
输出格式
对于每个k=2输出一个答案

备注
范围:20%的数据保证,n,m<=100
     
60%的数据保证,n <=1000,m<=50000
     
100%的数据保证,n,m<=50000
注意:树是可以重叠的,比如1号位置上可以种多种树

解析:这题可以这么做,建立两棵线段树,分别维护这个点之前有几个左括号和这个点之后有几个右括号,于是就可以做啦。

代码:

#include<iostream>
#include<cstdio>
using namespace std;

struct node{
    int s,t,l,r;
}tr[800001];
int n,q;
int a[200001];

int read()
{
    char c=getchar();
    int a=0;
    while (c<‘0‘||c>‘9‘) c=getchar();
    while (c>=‘0‘&&c<=‘9‘)
    {
          a=a*10+c-‘0‘;
          c=getchar();
    }
    return a;
}

void build(int k,int x,int y)
{
    tr[k].s=x; tr[k].t=y;
    if (x==y) { tr[k].l=tr[k].r=0; return; }
    int mid=(x+y)>>1;
    build(k<<1,x,mid);
    build(k<<1|1,mid+1,y);
    return;
}

void insertl(int now,int x,int y)
{
    int l=tr[now].s,r=tr[now].t;
    //if (y
    if (x==l && y==r)
    {
        tr[now].l+=1;
        return;
    }
    int mid=(l+r)>>1;
    if (x>mid) insertl(now<<1|1,x,y);
        else if (y<=mid) insertl(now<<1,x,y);
            else { insertl(now<<1,x,mid); insertl(now<<1|1,mid+1,y);        }
    return;
}

void insertr(int now,int x,int y)
{
    int l=tr[now].s,r=tr[now].t;
    //if (y
    if (x==l && y==r)
    {
        tr[now].r+=1;
        return;
    }
    int mid=(l+r)>>1;
    if (x>mid) insertr(now<<1|1,x,y);
        else if (y<=mid) insertr(now<<1,x,y);
            else { insertr(now<<1,x,mid); insertr(now<<1|1,mid+1,y);        }
    return;
}

int findl(int k,int x)
{
    int l=tr[k].s,r=tr[k].t;
    //if (y
    if (l==r) return tr[k].l;
    int mid=(l+r)>>1;
    if (x<=mid) return tr[k].l+findl(k<<1,x);
        else return tr[k].l+findl(k<<1|1,x);

}

int findr(int k,int x)
{
    int l=tr[k].l,r=tr[k].r;
    if (l==r) return tr[k].r;
    int mid=(l+r)>>1;
    if (x<=mid) return tr[k].r+findr(k<<1,x);
        else return tr[k].r+findr(k<<1|1,x);
}

int main()
{
        int total=0;
        n=read();
        build(1,0,n);
        q=read();
        for (int i=1; i<=q; i++)
        {
            int now=read();
            int x=read(),y=read();
            if (now==1)
            {
                insertl(1,0,x-1);
                insertr(1,y+1,n);
                total++;
            }
            else if (now==2)
            {
                int ans1=findr(1,x);
                int ans2=findl(1,y);
                int ans=ans1+ans2;
                //cout << ans1 << ‘ ‘ << ans2 << "hh"  << endl;
                printf("%lld\n",total-ans);
            }
        }
        return 0;
}
时间: 2024-12-11 17:45:17

回档|校门外的树3|线段树的应用的相关文章

[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log n). 代码 树状数组套线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> usin

【vijos】1750 建房子(线段树套线段树+前缀和)

https://vijos.org/p/1750 是不是我想复杂了.... 自己yy了个二维线段树,然后愉快的敲打. 但是wa了两法.......sad 原因是在处理第二维的更新出现了个小问题,sad. void pushup1(int x) { for1(i, 1, mm<<2) mn[x][i]=min(mn[lc][i], mn[rc][i]); } 这里注意是mm*4...我该好好想想了..这是在dbg的时候找出来的问题.sad. 我觉得很奇怪,线段树的底层节点一共就mm个,那么整棵树

【bzoj4785】[Zjoi2017]树状数组 线段树套线段树

题目描述 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1) mod 2. 2 l r,表示询问 sigma(Ai) mod 2,L<=i<=r 尽管那个时候的可怜非常的 simple,但是她还是发现这题可以用树状数组做.当时非常young 的她写了如下的算法: 1: function Add(x

UVALive 7148 LRIP【树分治+线段树】

题意就是要求一棵树上的最长不下降序列,同时不下降序列的最小值与最大值不超过D. 做法是树分治+线段树,假设树根是x,y是其当前需要处理的子树,对于子树y,需要处理出两个数组MN,MX,MN[i]表示以x为第一个数字的不下降子序列中第i个数的最小值,MX[i]表示以x为第一个数字的不上升子序列中第i个数的最大值.如果当前子树有一个以x为首的不下降序列,那么我们就需要在之前处理的子树中找一条以x为首的满足约束条件不上升序列,可以用线段树来查询.同时每做完一颗子树的时候,用MN,MX对线段树进行更新.

区间树和线段树

注意:区间树和线段树不一样哦,线段树是一种特殊的区间树. 区间树: 区间树是在红黑树基础上进行扩展得到的支持以区间为元素的动态集合的操作,其中每个节点的关键值是区间的左端点.通过建立这种特定的结构,可是使区间的元素的查找和插入都可以在O(lgn)的时间内完成.相比于基础的红黑树数据结构,增加了一个max[x],即以x为根的子树中所有区间的断点的最大值.逻辑结构如下所示: 区间树具有和红黑树一样的性质,并且区间树的基础操作和红黑树的基础操作一样.(具体红黑树的操作,参见http://blog.cs

主席树/函数式线段树/可持久化线段树

什么是主席树 可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本.同时充分利用它们之间的共同数据来减少时间和空间消耗. 因此可持久化线段树也叫函数式线段树又叫主席树. 可持久化数据结构 在算法执行的过程中,会发现在更新一个动态集合时,需要维护其过去的版本.这样的集合称为是可持久的. 实现持久集合的一种方法时每当该集合被修改时,就将其整个的复制下来,但是这种方法会降低执行速度并占用过多的空间. 考虑一个持久集合S. 如图所示,对集合的

二分索引树与线段树分析

二分索引树是一种树状数组,其全名为Binary Indexed Tree.二分索引树可以用作统计作用,用于计某段连续区间中的总和,并且允许我们动态变更区间中存储的值.二分索引树和线段树非常相似,二者都享有相同的O(log2(n))时间复杂度的更新操作和O(log2(n))时间复杂度的查询操作,区别在于二分索引树更加简洁高效,而线段树则较冗杂低效,原因在于对二分索引树的操作中是使用了计算机中整数存储的特性来进行加速,而线段树中由于使用的是比较操作,因此性能不及二分索引树.那么为什么我们不抛弃线段树

hdu-4819-线段树套线段树

http://acm.hdu.edu.cn/showproblem.php?pid=4819 给出一个N*N的矩阵,每次询问一个m*m的子矩阵里的floor((maxv+minv)/2)并把中间的元素修改为这个值. 线段树套线段树,第一层X表示对行建立的线段树,内层表示对Y也就是列建立的线段树. 分别对X和Y建立相应的函数来完成操作,当更新X树的节点时,再更新完当前X的节点的左右儿子之后,回头对X的这个节点对应的Y树进行更新,相当于X的左右儿子里的Y树来更新X的Y树,能理解这一点就很简单了. 1

ZJOI 2017 树状数组(线段树套线段树)

题意 http://uoj.ac/problem/291 思路 不难发现,九条カレン醬所写的树状数组,在查询区间 \([1,r]\) 的时候,其实在查询后缀 \([r,n]\) :在查询 \([l,r](l\neq1)\) 的时候,则是在查询 \([l-1,r-1]\) .那么在查询 \([1,r]\) 的时候,只需要询问 \(r\) 的前后缀异或是否相等:在查询 \([l,r](l\neq 1)\) 的时候,只需要询问 \(a[l-1],a[r]\) 是否相等. 考虑 \(O(n^2)\) 的