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 ...
随机推荐
- 串String(1):串的实现(定长顺序存储结构)
前言 PS:本文相关头文件.预编译以及typedef如下,阅读一遍以便于下面的理解: #include <stdio.h> #include <stdlib.h> #inclu ...
- linux系统下,安装centos7.0系统,配置网卡出现的问题(与centos5.x、centos6.x版本,有差异)
1.新建虚拟机时,自己下载的是centos64系统,选择系统时,默认选择centos,而未选择centos64位,导致犯了一个低级错误,导致后面网卡安装一直有问题 2.查看ip命令与centos5.x ...
- ArcGIS API for JavaScript 4.2学习笔记[10] 2D添加指北针widget、视图保存、视图padding(第二章完结)
这几个例子是第二章除了入门之外比较简单的几个,就做个合集,把最核心的代码(第二参数)和 引用放上来即可,不作多解释. 2D地图添加指北针widget 2D地图一般修正方向为正北方就需要这个widget ...
- 深入学习rollup来进行打包
深入学习rollup来进行打包 阅读目录 一:什么是Rollup? 二:如何使用Rollup来处理并打包JS文件? 三:设置Babel来使旧浏览器也支持ES6的代码 四:添加一个debug包来记录日志 ...
- sql server 2012 新知识-序列
今天聊一聊sql 2012 上的新功能-----序列 按我的理解,它就是为了实现全局性的唯一标识,按sql server 以前的版本,想对一张表标识很简单,比如identity,但如果要对某几张有业务 ...
- SecureCRT连接本地的Vmware虚拟机(CentOS)时提示连接超时“Connection timed out”
测试了一下,直接在Vmware的VM里面可以ping通宿主机. 但是宿主机无法ping通VM. 后面发现是本地的网络设置里面的vmware的NAT的网卡设置了手工填写地址和DNS. 修改为自动获取.问 ...
- 移动端的一些常用meta标签
<!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --> <html lang="zh-cmn-Hans"&g ...
- Struts2-整理笔记(二)常量配置、动态方法调用、Action类详解
1.修改struts2常量配置(3种) 第一种 在str/struts.xml中添加constant标签 <struts> <!-- 如果使用使用动态方法调用和include冲突 - ...
- SQL重复记录查询的几种方法
http://www.jb51.net/article/34820.htm \ 1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断 复制代码 代码如下: select * f ...
- 15个超强悍的CSS3圆盘时钟动画赏析
在网页上,特别是个人博客中经常会用到时钟插件,一款个性化的时钟插件不仅可以让页面显得美观,而且可以让访客看到当前的日期和时间.今天我们给大家收集了15个超强悍的圆盘时钟动画,很多都是基于CSS3,也有 ...