Vijos P1448 校门外的树【多解,线段树,树状数组,括号序列法+暴力优化】
校门外的树
描述
校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
K=1,K=1,读入l、r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同
K=2,读入l,r表示询问l~r之间能见到多少种树
(l,r>0)
格式
输入格式
第一行n,m表示道路总长为n,共有m个操作
接下来m行为m个操作
输出格式
对于每个k=2输出一个答案
样例1
样例输入1
5 4
1 1 3
2 2 5
1 2 4
2 3 5
样例输出1
1
2
限制
1s
提示
范围:20%的数据保证,n,m<=100
60%的数据保证,n <=1000,m<=50000
100%的数据保证,n,m<=50000
来源
dejiyu@CSC WorkGroup
分析:这题目从上午九点写到下午四点,历经七个小时的磨难,只为给大家提供最优质的方法!
这道题我用了三种方法去解决!
第一种:线段树【时间花费最长,也最伤脑的写法】,做法是将[a,b]种上一种树,这个修改操作影响的询问满足,
询问区间与[a,b]有交,转化为统计总修改数-与某询问交为空集的修改数
对于一个修改操作[l,r],与它为空集的询问[a,b]满足a∈[1,l-1]或者b∈[r+1,n]
用两棵线段树维护,修改[l,r],将第一棵的[1,l-1]区间+1,第二棵[r+1,n]区间+1
询问[a,b],答案为之前的修改数-(第一棵单点询问b+第二棵单点询问a)
代码中线段树结点的l,r其实就是两棵线段树。。。标记永久化
下面给出线段树的代码:
#include <bits/stdc++.h>
using namespace std;
const int N=;
int n,m;
inline int read()
{
int x=,f=;
char ch=getchar();
while(ch<''||ch>'')
{
if(ch=='-')
f=-;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=x*+ch-'';
ch=getchar();
}
return x*f;
}
inline void write(int x)
{
if(x<)
{
putchar('-');
x=-x;
}
if(x>)
{
write(x/);
}
putchar(x%+'');
}
struct Tree
{
int l,r;
int left,right;
}tree[N<<];
inline void buildtree(int x,int y,int pos)
{
tree[pos].left=x;
tree[pos].right=y;
if(x==y)
{
return;
}
int mid=(x+y)/;
buildtree(x,mid,pos*);
buildtree(mid+,y,pos*+);
}
inline void insertl(int x,int y,int pos)
{
int l=tree[pos].left;
int r=tree[pos].right;
if(l==x&&r==y)
{
tree[pos].l++;
return;
}
int mid=(l+r)/;
if(y<=mid)
insertl(x,y,pos*);
else if(x>mid)
insertl(x,y,pos*+);
else
{
insertl(x,mid,pos*);
insertl(mid+,y,pos*+);
}
}
inline void insertr(int x,int y,int pos)
{
int l=tree[pos].left;
int r=tree[pos].right;
if(l==x&&r==y)
{
tree[pos].r++;
return;
}
int mid=(l+r)/;
if(y<=mid)
insertr(x,y,pos*);
else if(x>mid)
insertr(x,y,pos*+);
else
{
insertr(x,mid,pos*);
insertr(mid+,y,pos*+);
}
}
inline int askl(int k,int x)
{
int l=tree[k].left;
int r=tree[k].right;
if(l==r)
return tree[k].l;
int mid=(l+r)/;
if(x<=mid)
return tree[k].l+askl(k*,x);
else return tree[k].l+askl(k*+,x);
}
inline int askr(int k,int x)
{
int l=tree[k].left;
int r=tree[k].right;
if(l==r)
return tree[k].r;
int mid=(l+r)/;
if(x<=mid)
return tree[k].r+askr(k*,x);
else return tree[k].r+askr(k*+,x);
}
int main()
{
n=read();
m=read();
int tot=;
buildtree(,n,);
for(int i=;i<=m;i++)
{
int t,a,b;
cin>>t>>a>>b;
if(t==)
{
insertl(,a-,);
insertr(b+,n,);
tot++;
}
else
{
int ans=askr(,a)+askl(,b);
write(tot-ans);
cout<<endl;
}
}
return ;
}
第二种写法:树状数组
做法:这题是一条条线段,所以我们可以用线段树之类的东东来实现,然后感觉树状数组写起来简单一点所以就打了
开两个数组来存一个是开始的点的数量,一个是结束的 ,然后随便搞一下,最后输出就可以了
下面给出树状数组写法:
#include <bits/stdc++.h>
using namespace std;
const int N=;
int l[N],r[N];
int n,m;
inline int read()
{
int x=,f=;
char ch=getchar();
while(ch<''||ch>'')
{
if(ch=='-')
f=-;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=x*+ch-'';
ch=getchar();
}
return x*f;
}
inline void write(int x)
{
if(x<)
{
putchar('-');
x=-x;
}
if(x>)
{
write(x/);
}
putchar(x%+'');
}
int lowbit(int x)
{
return x&-x;
}
void add(int x,int d,int c[])
{
while(x<=n)
{
c[x]+=d;
x+=lowbit(x);
}
}
int sum(int x,int c[])
{
int s=;
while(x>)
{
s+=c[x];
x-=lowbit(x);
}
return s;
}
int main()
{
int k,x,y;
n=read();
m=read();
for(int i=;i<=m;i++)
{
cin>>k>>x>>y;
if(k==)
{
add(x,,l);
add(y,,r);
}
else
{
write(sum(y,l)-sum(x-,r));
cout<<endl;
}
}
return ;
}
第三种方法:括号序列法【简称括号法】

以上就是括号序列的过程。简单的说,就是更新区间[a,b]时,点a记录左括号数,点b记录右括号数,查询区间[a,b]时,即为b之前(包括b)的左括号数-a之前的右括号数。
#include <bits/stdc++.h>
using namespace std;
const int N=;
int l[N],r[N];
int n,m;
inline int read()
{
int x=,f=;
char ch=getchar();
while(ch<''||ch>'')
{
if(ch=='-')
f=-;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=x*+ch-'';
ch=getchar();
}
return x*f;
}
inline void write(int x)
{
if(x<)
{
putchar('-');
x=-x;
}
if(x>)
{
write(x/);
}
putchar(x%+'');
}
int main()
{
int k,x,y;
n=read();
m=read();
for(int i=;i<=m;i++)
{
cin>>k>>x>>y;
if(k==)
{
for(int j=x;j<=n;j+=j&-j)
l[j]++;
for(int j=y;j<=n;j+=j&-j)
r[j]++;
}
else
{
int ans=;
for(int j=y;j;j-=j&-j)
ans+=l[j];
for(int j=x-;j;j-=j&-j)
ans-=r[j];
write(ans);
cout<<endl;
}
}
return ;
}
Vijos P1448 校门外的树【多解,线段树,树状数组,括号序列法+暴力优化】的更多相关文章
- vijos P1448 校门外的树
描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的--如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:\(K=1\),读入\(l, ...
- 【vijos】P1448 校门外的树
[题意]两种操作,[L,R]种新的树(不覆盖原来的),或查询[L,R]树的种类数.n<=50000. [算法]树状数组||线段树 [题解]这题可以用主席树实现……不过因为不覆盖原来的,所以有更简 ...
- Vijos P1103 校门外的树【线段树,模拟】
校门外的树 描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……, ...
- vijos 1448 校门外的树 树状数组
描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r表 ...
- vijos 1448 校门外的树 (不是05年普及组那题)
描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r表 ...
- Ping pong(树状数组求序列中比某个位置上的数小的数字个数)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2492 Ping pong Time Limit: 2000/1000 MS (Java/Others) ...
- spoj227 树状数组插队序列问题
插队问题和线段树解决的方式一样,每个结点维护值的信息是该节点之前的空位有多少,然后从后往前插点即可 注意该题要求输出的是从左往右输出每个士兵的等级,即问士兵最后排在第几个位置 /* 树状数组维护前i个 ...
- POJ--3321 Apple Tree(树状数组+dfs(序列))
Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 22613 Accepted: 6875 Descripti ...
- 【NOI P模拟赛】校门外歪脖树上的鸽子(树链剖分)
题面 2 ≤ n ≤ 2 × 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 , 1 ≤ l ≤ r ≤ n , 1 ≤ d ≤ 1 0 8 2 ≤ n ≤ 2 × 10^5,1 ≤ m ≤ 2 ...
随机推荐
- php面向对象4
成员属性 基本介绍 成员属性是类的一个组成部分,一般是基本数据类型,也可以是复合类型,资源类型.比如 public $age;就是成员属性 说明 ①成员属性可以是php的任何数据类型(int, flo ...
- bash shell快捷键[转]
生活在 Bash shell 中,熟记以下快捷键,将极大的提高你的命令行操作效率. 编辑命令 Ctrl + a :移到命令行首 Ctrl + e :移到命令行尾 Ctrl + f :按字符前移(右向) ...
- ExperDot的博客目录导航
最近活动 我更新了博客!粒子系统:从零开始画一棵树 Github:[ UWP ] [ JavaScript ] 自然编程 奇幻元纪 上帝创世篇:如何画一颗静态树 女娲补天篇:仿人工拼接碎片 吴刚伐桂 ...
- uptime 命令详解
作用: 打印系统总共运行了多长时间和系统的平均负载. uptime 命令可以显示的信息依次为: 现在时间, 系统已经运行时间, 目前登录用户个数, 系统1,5,15 分钟内的平均负载 实例: up ...
- tee 命令详解
作用:将数据重定向到文件,另一方面还可以提供一份重定向数据的副本作为后续命令的stdin . 简单的说就是把数据重定向给文件和屏幕上. 注意:存在缓存机制,每1024 字节输出一次, 若从管道接受数据 ...
- CGO 类型(CGO Types) 一
CGO Types C作为一种混合编程语言已经很久了,无论那些广泛使用的包是用何种语言实现的,都导出了和C兼容的API.Go程序调用C程序,可以借助两种工具实现,一种是cgo,另一种是SWIG工具.C ...
- Shader 1:能接受阴影的透明shader
第一次接触Shader,项目需要,直接说需求吧,需要一个透明并且能接受阴影的shader.unity系统自带的shader已经满足不了了.上一段代码吧 Shader "GreenArch/T ...
- 滚动条大于120px时,判断pc端的情况下,导航条固定定位
//滚动条大于120px时,判断pc端的情况下,导航条固定定位 $(window).scroll(function(){ var viewWidth=$(document).width() var ...
- [编织消息框架][JAVA核心技术]动态代理应用12-总结
动态代理这篇比较长,是框架组成的重要基础 回顾下学到的应用技术 1.异常应用 2.annotation技术 3.数值与逻辑分享 4.jdk.cglib.javassist等动态代理技术 5.懒处理.预 ...
- python核心编写视频笔记--模块的导入
1. 模块的重新导入 有这样的一种情况:我们首先创建了一个.py文件,输入模块代码.保存后,我们进入ipython3的环境,引入这个模块.然后再ipython3环境外修改这个模块文件,在ipython ...