[离散化+树状数组]CodeForces - 652D Nested Segments
2 seconds
256 megabytes
standard input
standard output
You are given n segments on a line. There are no ends of some segments that coincide. For each segment find the number of segments it contains.
The first line contains a single integer n (1 ≤ n ≤ 2·105) — the number of segments on a line.
Each of the next n lines contains two integers li and ri ( - 109 ≤ li < ri ≤ 109) — the coordinates of the left and the right ends of the i-th segment. It is guaranteed that there are no ends of some segments that coincide.
Print n lines. The j-th of them should contain the only integer aj — the number of segments contained in the j-th segment.
4
1 8
2 3
4 7
5 6
3
0
1
0
3
3 4
1 5
2 6
0
1
1
题意:一条线上有n条直线,没有两个线段有相同的端点,要求每个线段各自包含了多少线段
下面有2种做法
思路1:
记录下右端点的坐标,记录下右端点的坐标,将右端点离散化,用树状数组维护右端点数量前缀和,
给左端点升序排序,从最左边的左端点开始找,
因为左端点升序,所以当前左端点要比所有右端点都小(一开始是满足的,接着我们要不断删去右端点来维护这种状态),当前左端点也比它后面的要小,如果它后面的左端点对应的右端点小于当前右端点,则那条线段是包含在当前线段中的),看当前这个右端点之前有多少个右端点就可知道当前这个线段包含了多少线段
因为我们要保证当前左端点要比所有右端点小才能使得只需统计当前右端点之前有多少右端点就能知道当前这个线段包含了多少线段,如果到了下一个左端点,则上一个线段就不包含在下一个线段中了,因此如果到了下一个左端点就要删掉上一个右端点,所以要删掉当前这个已经找过的右端点
思路2:
记录下右端点的坐标,记录下右端点的坐标,将右端点离散化,用树状数组维护右端点数量前缀和,
给左端点降序排序,从最右边的左端点开始找
因为左端点降序排序,所以当前左端点后都没有比它大的未计算过的左端点,如果比它大的左端点被计算过了且那个左端点对应的右端点比现在这个左端点对应的右端点小,则那条线段必定被当前线段包含,所以按左端点降序的顺序添加对应的右端点,可以保证当前没有右端点比当前左端的小
总结:
两种思路的共同点都是要保证当前左端点之前没有比它小的右端点,这样就只需要统计当前左端点对应的右端点之前有多少个右端点就可以知道当前这条线段包含了多少线段,他们的不同点在于思路1是提前把所有的右端的都加进去了,每次查询的时候再删,而思路2是先从最大的左端点开始添加右端点
思路1代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int amn=2e5+;
int bit[amn],n,tp,b[amn];
struct node{
int l,r,id;
} a[amn];
int ans[amn],jg[amn],pos;
map<ll,int> mp;
bool cmp(node a,node b){
if(a.r==b.r)return a.r<b.r;
return a.l<b.l;
}
int sum(int i){
int s=;
while(i){
s+=bit[i];
i-=i&-i;
}
return s;
}
void add(int i,int x){
while(i<=tp){
bit[i]+=x;
i+=i&-i;
}
}
int main(){
ios::sync_with_stdio();
cin>>n;
tp=;
for(int i=;i<=n;i++){
a[i].id=i; ///记录原始顺序
cin>>a[i].l>>a[i].r;
b[++tp]=a[i].r; ///记录下右端点的坐标
ans[i]=; ///初始化答案数组
}
sort(b+,b++tp); ///给右端点的坐标排序
int mtp=;
for(int i=;i<=tp;i++){
mp[b[i]]=mtp; ///将右端点离散化
mtp++;
}
for(int i=;i<=n;i++){
add(mp[a[i].r],); ///用树状数组维护右端点数量前缀和
}
sort(a+,a++n,cmp); ///给左端点升序排序,从最左边的左端点开始找
for(int i=;i<=n;i++){
ans[a[i].id]=sum(mp[a[i].r]-); ///因为左端点升序,所以当前左端点要比所有未计算过的右端点都小(一开始是满足的,接着我们要不断删去右端点来维护这种状态),当前左端点也比它后面的要小,如果它后面的左端点对应的右端点小于当前右端点,则那条线段是包含在当前线段中的),看当前这个右端点之前有多少个右端点就可知道当前这个线段包含了多少线段
add(mp[a[i].r],-); ///因为我们要保证当前左端点要比所有右端点小才能使得只需统计当前右端点之前有多少右端点就能知道当前这个线段包含了多少线段,如果到了下一个左端点,则上一个线段就不包含在下一个线段中了,因此如果到了下一个左端点就要删掉上一个右端点,所以要删掉当前这个已经找过的右端点
}
for(int i=;i<=n;i++){
printf("%d\n",ans[i]);
}
}
/***
一条线上有n条直线,没有两个线段有相同的端点,要求每个线段各自包含了多少线段
记录下右端点的坐标,记录下右端点的坐标,将右端点离散化,用树状数组维护右端点数量前缀和,
给左端点升序排序,从最左边的左端点开始找,
因为左端点升序,所以当前左端点要比所有未计算过的右端点都小(一开始是满足的,接着我们要不断删去右端点来维护这种状态),当前左端点也比它后面的要小,如果它后面的左端点对应的右端点小于当前右端点,则那条线段是包含在当前线段中的),看当前这个右端点之前有多少个右端点就可知道当前这个线段包含了多少线段
因为我们要保证当前左端点要比所有右端点小才能使得只需统计当前右端点之前有多少右端点就能知道当前这个线段包含了多少线段,如果到了下一个左端点,则上一个线段就不包含在下一个线段中了,因此如果到了下一个左端点就要删掉上一个右端点,所以要删掉当前这个已经找过的右端点
***/
思路2代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int amn=2e5+;
int bit[amn],n,tp,b[amn];
struct node{
int l,r,id;
} a[amn];
int ans[amn],jg[amn],pos;
map<ll,int> mp;
bool cmp1(node a,node b){
if(a.r==b.r)return a.r>b.r;
return a.l>b.l;
}
int sum(int i){
int s=;
while(i){
s+=bit[i];
i-=i&-i;
}
return s;
}
void add(int i,int x){
while(i<=tp){
bit[i]+=x;
i+=i&-i;
}
}
int main(){
ios::sync_with_stdio();
cin>>n;
tp=;
for(int i=;i<=n;i++){
a[i].id=i; ///记录原始顺序
cin>>a[i].l>>a[i].r;
b[++tp]=a[i].r; ///记录下右端点的坐标
ans[i]=; ///初始化答案数组
}
sort(b+,b++tp); ///给右端点的坐标排序
int mtp=;
for(int i=;i<=tp;i++){
mp[b[i]]=mtp; ///将右端点离散化
mtp++;
}
sort(a+,a++n,cmp1); ///给左端点降序排序,从最右边的左端点开始找
for(int i=;i<=n;i++){
add(mp[a[i].r],); ///因为左端点降序排序,所以当前左端点后都没有比它大的未计算过的左端点,如果比它大的左端点被计算过了且那个左端点对应的右端点比现在这个左端点对应的右端点小,则那条线段必定被当前线段包含,所以按左端点降序的顺序添加对应的右端点,可以保证当前没有右端点比当前左端的小
ans[a[i].id]=sum(mp[a[i].r]-);
}
for(int i=;i<=n;i++){ ///两种思路的共同点都是要保证当前左端点之前没有比它小的右端点,这样就只需要统计当前左端点对应的右端点之前有多少个右端点就可以知道当前这条线段包含了多少线段,他们的不同点在于思路1是提前把所有的右端的都加进去了,每次查询的时候再删,而思路2是先从最大的左端点开始添加右端点
printf("%d\n",ans[i]);
}
}
/***
一条线上有n条直线,没有两个线段有相同的端点,要求每个线段各自包含了多少线段
记录下右端点的坐标,记录下右端点的坐标,将右端点离散化,用树状数组维护右端点数量前缀和,
给左端点降序排序,从最右边的左端点开始找
因为左端点降序排序,所以当前左端点后都没有比它大的未计算过的左端点,如果比它大的左端点被计算过了且那个左端点对应的右端点比现在这个左端点对应的右端点小,则那条线段必定被当前线段包含,所以按左端点降序的顺序添加对应的右端点,可以保证当前没有右端点比当前左端的小
两种思路的共同点都是要保证当前左端点之前没有比它小的右端点,这样就只需要统计当前左端点对应的右端点之前有多少个右端点就可以知道当前这条线段包含了多少线段,他们的不同点在于思路1是提前把所有的右端的都加进去了,每次查询的时候再删,而思路2是先从最大的左端点开始添加右端点
***/
[离散化+树状数组]CodeForces - 652D Nested Segments的更多相关文章
- Code Forces 652D Nested Segments(离散化+树状数组)
Nested Segments time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...
- CodeForces 540E - Infinite Inversions(离散化+树状数组)
花了近5个小时,改的乱七八糟,终于A了. 一个无限数列,1,2,3,4,...,n....,给n个数对<i,j>把数列的i,j两个元素做交换.求交换后数列的逆序对数. 很容易想到离散化+树 ...
- HDU 5862 Counting Intersections(离散化+树状数组)
HDU 5862 Counting Intersections(离散化+树状数组) 题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=5862 D ...
- Ultra-QuickSort(归并排序+离散化树状数组)
Ultra-QuickSort Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 50517 Accepted: 18534 ...
- CodeForces 652D Nested Segments
离散化+树状数组 先对坐标离散化,把每条线段结尾所在点标1, 询问某条线段内有几条线段的时候,只需询问这段区间的和是多少,询问结束之后再把这条线段尾部所在点标为0 #include<cstdio ...
- BZOJ_4627_[BeiJing2016]回转寿司_离散化+树状数组
BZOJ_4627_[BeiJing2016]回转寿司_离散化+树状数组 Description 酷爱日料的小Z经常光顾学校东门外的回转寿司店.在这里,一盘盘寿司通过传送带依次呈现在小Z眼前.不同的寿 ...
- poj-----Ultra-QuickSort(离散化+树状数组)
Ultra-QuickSort Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 38258 Accepted: 13784 ...
- hdu 3015 Disharmony Trees (离散化+树状数组)
Disharmony Trees Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 【bzoj4627】[BeiJing2016]回转寿司 离散化+树状数组
题目描述 给出一个长度为n的序列,求所有元素的和在[L,R]范围内的连续子序列的个数. 输入 第一行包含三个整数N,L和R,分别表示寿司盘数,满意度的下限和上限. 第二行包含N个整数Ai,表示小Z对寿 ...
随机推荐
- Spring Boot 2.x基础教程:使用 Thymeleaf开发Web页面
通过本系列教程的前几章内容(API开发.数据访问).我们已经具备完成一个涵盖数据存储.提供HTTP接口的完整后端服务了.依托这些技能,我们已经可以配合前端开发人员,一起来完成一些前后端分离的Web项目 ...
- webpack环境配置2
1.webpack安装 Step 1: 首先安装Node.js, 在1中已经详细介绍了. Step2: 在Git或者cmd中输入下面这段代码, 通过全局先将webpack指令安装进电脑中npm ins ...
- 设计模式-09装饰模式(Decorator Pattern)
1.模式动机 一般有两种方式可以实现给一个类或对象增加行为: 继承机制:使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法.但是这种方法是 ...
- java基础进阶篇(二)_Arraylist ------【java源码栈】
前言 ArrayList 在开发中用到的频率很高,其中原生态提供的方法有一些很好用的重载版本,其中有的坑该跳得跳啊. 一.ArrayList的6种初始化方法1.构造方法 参数为空2.构造方法 参数为L ...
- 达拉草201771010105《面向对象程序设计(java)》第四周学习总结
实验四类与对象的定义及使用 实验时间 2018-9-20 第一部分:理论知识 1.类与对象概念 (1)类是具有相同属性和方法的一类事物的抽象,是构造对象的模板或蓝图,由类构造对象的过程称为创建类的实例 ...
- Flutter Widgets 对话框-Dialog
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 当应用程序进行重要操作时经常需要用户进行2次确认,以避免用 ...
- ubuntu下安装typescript
安装ts之前需要安装好node, 安装ts: 1. npm install -g typescript /opt/node/bin/tsc -> /opt/node/lib/node_modul ...
- 关于毕业五年PHP成长疑惑
1.PHP语法基础是否都会,比如异常捕捉,面向对象,数组操作语法,字符串操作,cookie,session,全局变量,超全局数组,防止sql注入,mysql预处理 2.MYSQL基础语法,字段设计,原 ...
- 【猫狗数据集】谷歌colab之使用pytorch读取自己数据集(猫狗数据集)
之前在:https://www.cnblogs.com/xiximayou/p/12398285.html创建好了数据集,将它上传到谷歌colab 在colab上的目录如下: 在utils中的rdat ...
- 【S2-053】Struts2远程命令执行漏洞(CVE-2017-12611)
继S2-052之后,Apache Struts 2再次被曝存在远程代码执行漏洞,漏洞编号S2-053,CVE编号CVE-2017-1000112. 当开发人员在Freemarker标签中使用错误的构造 ...