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
题目链接:https://vijos.org/p/1448
分析:这题目从上午九点写到下午四点,历经七个小时的磨难,只为给大家提供最优质的方法!
这道题我用了三种方法去解决!
第一种:线段树【时间花费最长,也最伤脑的写法】,做法是将[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其实就是两棵线段树。。。标记永久化
下面给出线段树的代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=500050; 4 int n,m; 5 inline int read() 6 { 7 int x=0,f=1; 8 char ch=getchar(); 9 while(ch<'0'||ch>'9') 10 { 11 if(ch=='-') 12 f=-1; 13 ch=getchar(); 14 } 15 while(ch>='0'&&ch<='9') 16 { 17 x=x*10+ch-'0'; 18 ch=getchar(); 19 } 20 return x*f; 21 } 22 inline void write(int x) 23 { 24 if(x<0) 25 { 26 putchar('-'); 27 x=-x; 28 } 29 if(x>9) 30 { 31 write(x/10); 32 } 33 putchar(x%10+'0'); 34 } 35 struct Tree 36 { 37 int l,r; 38 int left,right; 39 }tree[N<<3]; 40 inline void buildtree(int x,int y,int pos) 41 { 42 tree[pos].left=x; 43 tree[pos].right=y; 44 if(x==y) 45 { 46 return; 47 } 48 int mid=(x+y)/2; 49 buildtree(x,mid,pos*2); 50 buildtree(mid+1,y,pos*2+1); 51 } 52 inline void insertl(int x,int y,int pos) 53 { 54 int l=tree[pos].left; 55 int r=tree[pos].right; 56 if(l==x&&r==y) 57 { 58 tree[pos].l++; 59 return; 60 } 61 int mid=(l+r)/2; 62 if(y<=mid) 63 insertl(x,y,pos*2); 64 else if(x>mid) 65 insertl(x,y,pos*2+1); 66 else 67 { 68 insertl(x,mid,pos*2); 69 insertl(mid+1,y,pos*2+1); 70 } 71 } 72 inline void insertr(int x,int y,int pos) 73 { 74 int l=tree[pos].left; 75 int r=tree[pos].right; 76 if(l==x&&r==y) 77 { 78 tree[pos].r++; 79 return; 80 } 81 int mid=(l+r)/2; 82 if(y<=mid) 83 insertr(x,y,pos*2); 84 else if(x>mid) 85 insertr(x,y,pos*2+1); 86 else 87 { 88 insertr(x,mid,pos*2); 89 insertr(mid+1,y,pos*2+1); 90 } 91 } 92 inline int askl(int k,int x) 93 { 94 int l=tree[k].left; 95 int r=tree[k].right; 96 if(l==r) 97 return tree[k].l; 98 int mid=(l+r)/2; 99 if(x<=mid) 100 return tree[k].l+askl(k*2,x); 101 else return tree[k].l+askl(k*2+1,x); 102 } 103 inline int askr(int k,int x) 104 { 105 int l=tree[k].left; 106 int r=tree[k].right; 107 if(l==r) 108 return tree[k].r; 109 int mid=(l+r)/2; 110 if(x<=mid) 111 return tree[k].r+askr(k*2,x); 112 else return tree[k].r+askr(k*2+1,x); 113 } 114 int main() 115 { 116 n=read(); 117 m=read(); 118 int tot=0; 119 buildtree(0,n,1); 120 for(int i=1;i<=m;i++) 121 { 122 int t,a,b; 123 cin>>t>>a>>b; 124 if(t==1) 125 { 126 insertl(0,a-1,1); 127 insertr(b+1,n,1); 128 tot++; 129 } 130 else 131 { 132 int ans=askr(1,a)+askl(1,b); 133 write(tot-ans); 134 cout<<endl; 135 } 136 } 137 return 0; 138 }
第二种写法:树状数组
做法:这题是一条条线段,所以我们可以用线段树之类的东东来实现,然后感觉树状数组写起来简单一点所以就打了
开两个数组来存一个是开始的点的数量,一个是结束的 ,然后随便搞一下,最后输出就可以了
下面给出树状数组写法:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=50050; 4 int l[N],r[N]; 5 int n,m; 6 inline int read() 7 { 8 int x=0,f=1; 9 char ch=getchar(); 10 while(ch<'0'||ch>'9') 11 { 12 if(ch=='-') 13 f=-1; 14 ch=getchar(); 15 } 16 while(ch>='0'&&ch<='9') 17 { 18 x=x*10+ch-'0'; 19 ch=getchar(); 20 } 21 return x*f; 22 } 23 inline void write(int x) 24 { 25 if(x<0) 26 { 27 putchar('-'); 28 x=-x; 29 } 30 if(x>9) 31 { 32 write(x/10); 33 } 34 putchar(x%10+'0'); 35 } 36 int lowbit(int x) 37 { 38 return x&-x; 39 } 40 void add(int x,int d,int c[]) 41 { 42 while(x<=n) 43 { 44 c[x]+=d; 45 x+=lowbit(x); 46 } 47 } 48 int sum(int x,int c[]) 49 { 50 int s=0; 51 while(x>0) 52 { 53 s+=c[x]; 54 x-=lowbit(x); 55 } 56 return s; 57 } 58 int main() 59 { 60 int k,x,y; 61 n=read(); 62 m=read(); 63 for(int i=1;i<=m;i++) 64 { 65 cin>>k>>x>>y; 66 if(k==1) 67 { 68 add(x,1,l); 69 add(y,1,r); 70 } 71 else 72 { 73 write(sum(y,l)-sum(x-1,r)); 74 cout<<endl; 75 } 76 } 77 return 0; 78 }
第三种方法:括号序列法【简称括号法】
以上就是括号序列的过程。简单的说,就是更新区间[a,b]时,点a记录左括号数,点b记录右括号数,查询区间[a,b]时,即为b之前(包括b)的左括号数-a之前的右括号数。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=50050; 4 int l[N],r[N]; 5 int n,m; 6 inline int read() 7 { 8 int x=0,f=1; 9 char ch=getchar(); 10 while(ch<'0'||ch>'9') 11 { 12 if(ch=='-') 13 f=-1; 14 ch=getchar(); 15 } 16 while(ch>='0'&&ch<='9') 17 { 18 x=x*10+ch-'0'; 19 ch=getchar(); 20 } 21 return x*f; 22 } 23 inline void write(int x) 24 { 25 if(x<0) 26 { 27 putchar('-'); 28 x=-x; 29 } 30 if(x>9) 31 { 32 write(x/10); 33 } 34 putchar(x%10+'0'); 35 } 36 int main() 37 { 38 int k,x,y; 39 n=read(); 40 m=read(); 41 for(int i=1;i<=m;i++) 42 { 43 cin>>k>>x>>y; 44 if(k==1) 45 { 46 for(int j=x;j<=n;j+=j&-j) 47 l[j]++; 48 for(int j=y;j<=n;j+=j&-j) 49 r[j]++; 50 } 51 else 52 { 53 int ans=0; 54 for(int j=y;j;j-=j&-j) 55 ans+=l[j]; 56 for(int j=x-1;j;j-=j&-j) 57 ans-=r[j]; 58 write(ans); 59 cout<<endl; 60 } 61 } 62 return 0; 63 }
Vijos P1448 校门外的树【多解,线段树,树状数组,括号序列法+暴力优化】相关推荐
- 【vijos】P1448 校门外的树
[题意]两种操作,[L,R]种新的树(不覆盖原来的),或查询[L,R]树的种类数.n<=50000. [算法]树状数组||线段树 [题解]这题可以用主席树实现--不过因为不覆盖原来的,所以有更简 ...
- Vijos P1103 校门外的树【线段树,模拟】
校门外的树 描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,--, ...
- vijos 1448 校门外的树 树状数组
描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的-- 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作: K=1,K=1,读入l. ...
- 机器学习算法(二十五):KD树详解及KD树最近邻算法
目录 1 KD树 1.1 什么是KD树 1.2 KD树的构建 1.3 KD树的插入 1.4 KD树的删除 1.5 KD树的最近邻搜索算法 1.5.1 举例:查询点(2.1,3.1) 1.5.2 举例: ...
- 奇小葩讲设备树(5/5)-- Linux设备树详解(五)设备树的使用
对于任何的知识来说,了解了理论的知识,知道了设备树怎么解析用以代替传统的范式之后,我们需要知道怎么使用设备树.对于使用我们分两部分,一部分是它有哪些接口,能做些什么,至于怎么编写dts文件本章不讨论. ...
- KD树详解及KD树最近邻算法
参考:http://blog.csdn.net/app_12062011/article/details/51986805 http://www.cnblogs.com/snake-hand/arch ...
- 【树】B032_LC_ 二叉树中的伪回文路径(暴力 / 优化)
一.Problem Given a binary tree where node values are digits from 1 to 9. A path in the binary tree is ...
- Loj 10115 「一本通 4.1 例 3」校门外的树 (树状数组)
题目链接:https://loj.ac/problem/10115 题目描述 原题来自:Vijos P1448 校门外有很多树,学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的 ...
- 「一本通 4.1 例 3」校门外的树 (loj10115)
题目描述 原题来自:Vijos P1448 校门外有很多树,学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两种操作: K=1,读入 l,r表示在 l 到 r 之间种上 ...
最新文章
- j函数 判断以 什么开头
- 【杂谈】如何在专家指导下系统性学习自然语言处理
- 岗位内推 | 微软亚洲互联网工程院自然语言处理组招聘
- 厉害了,在Pandas中用SQL来查询数据,效率超高
- Consul-template+nginx实现自动负载均衡
- nginx fastcgi python_webpy + nginx + fastcgi 构建python应用
- 安卓手机卡顿怎么解决_手机卡顿怎么办? 几招教你轻松解决!
- node.js与python_Node.js与Python
- 三菱plc pwm指令_常用PLC各系列简介大全,选型必看!
- Ubuntu20.04 安装向日葵SunloginClient并解决报错缺少依赖问题
- 如何安装老版本Eclipse汉化——以2020-06为例
- 计算机组装维修中级试题,维修电工中级培训考试题及答案
- element技巧之element的dialog弹出框可拖拽、可拉伸、可全屏并处理边界问题
- 垃圾邮件服务器 查询,邮件服务器ip黑名单查询
- 机器学习——算法介绍-4
- TestCenter Layer4-7分析
- 深入理解char * ,char ** ,char a[ ] ,char *a[]
- html 带箭头的提示框,css实现对话框-带箭头提示框
- 进入外包公司之后…………
- 最短路(两种常用算法!!!)
热门文章
- ubuntu下rar文件解压后文件名乱码的解决方案
- Waymo也商业化了!“早期乘客”项目开始测试收费,凤凰城人民掏了腰包
- Javascript知识汇总------获取构造函数constructor名称和一些字符串处理方法
- Gym - 101194F(后缀数组)
- Problem 69:Totient maximum
- [剑指Offer]9.用两个栈实现队列
- 【命令小结】“|”的用法
- linux下图形远程桌面
- Linux下限制用户通过SFTP访问指定目录
- 通过telnet自动下载cfg配置文件