Nested Segments
time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

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.

Input

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.

Output

Print n lines. The j-th of them should contain the only integer aj — the number of segments contained in the j-th segment.

Examples
input

Copy
4
1 8
2 3
4 7
5 6
output

Copy
3
0
1
0
input

Copy
3
3 4
1 5
2 6
output

Copy
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的更多相关文章

  1. Code Forces 652D Nested Segments(离散化+树状数组)

     Nested Segments time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  2. CodeForces 540E - Infinite Inversions(离散化+树状数组)

    花了近5个小时,改的乱七八糟,终于A了. 一个无限数列,1,2,3,4,...,n....,给n个数对<i,j>把数列的i,j两个元素做交换.求交换后数列的逆序对数. 很容易想到离散化+树 ...

  3. HDU 5862 Counting Intersections(离散化+树状数组)

    HDU 5862 Counting Intersections(离散化+树状数组) 题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=5862 D ...

  4. Ultra-QuickSort(归并排序+离散化树状数组)

    Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 50517   Accepted: 18534 ...

  5. CodeForces 652D Nested Segments

    离散化+树状数组 先对坐标离散化,把每条线段结尾所在点标1, 询问某条线段内有几条线段的时候,只需询问这段区间的和是多少,询问结束之后再把这条线段尾部所在点标为0 #include<cstdio ...

  6. BZOJ_4627_[BeiJing2016]回转寿司_离散化+树状数组

    BZOJ_4627_[BeiJing2016]回转寿司_离散化+树状数组 Description 酷爱日料的小Z经常光顾学校东门外的回转寿司店.在这里,一盘盘寿司通过传送带依次呈现在小Z眼前.不同的寿 ...

  7. poj-----Ultra-QuickSort(离散化+树状数组)

    Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 38258   Accepted: 13784 ...

  8. hdu 3015 Disharmony Trees (离散化+树状数组)

    Disharmony Trees Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  9. 【bzoj4627】[BeiJing2016]回转寿司 离散化+树状数组

    题目描述 给出一个长度为n的序列,求所有元素的和在[L,R]范围内的连续子序列的个数. 输入 第一行包含三个整数N,L和R,分别表示寿司盘数,满意度的下限和上限. 第二行包含N个整数Ai,表示小Z对寿 ...

随机推荐

  1. C++走向远洋——39(指向学生类的指针)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:zhizhen.cpp * 作者:常轩 * 微信公众号:Worl ...

  2. 一文搞懂jvm内存结构

    一.jvm是干什么的? 大家都知道java是跨平台语言,一次编译可以在不同操作系统上运行,怎么做到的呢,看下图: javac把写的源代码(java文件),编译成字节码(class文件),字节码部署到l ...

  3. web资源预加载-生产环境实践

    此文记录资源预加载在我们项目的实践,技术难度不算高,重在介绍一套技术方案的诞生与实施,其中都进行了哪些思考,依据什么来做决策,如何进行效果评估,等等.为读者在制定技术方案时提供一定启示. 背景 资源预 ...

  4. boostrap3 bootstrap-datetimepicker.min.js设置中文语言

    问题 bootstrap3中使用bootstrap-datetimepicker遇到设置中文语言的问题 解决办法 bootstrap-datetimepicker在使用的时候要先引入momentjs中 ...

  5. Typora[MarkDown编辑器]+(PicGo+Github+JsDelivr)[个人图床] ,开启你的高效创作

    使用Typora搭配Picgo开启你的高效创作 0x00 一切都要从MarkDown说起 富文本语言的弊端 平常我们最常用的写作工具,无非是富文本编辑器中的代表--微软家的Office Word.这种 ...

  6. XCTF---easyjni的WriteUp

    一.题目来源     题目来源:XCTF的mobile区的easyjni题目.     题目下载地址:题目链接地址 二.解题过程     1.下载好题目后,安装到夜神模拟器中,发现有一个输入框和一个按 ...

  7. 基于FPGA的三段式状态机

    状态机分类: 通常, 状态机的状态数量有限, 称为有限状态机(FSM) .由于状态机所有触发器的时钟由同一脉冲边沿触发, 故也称之为同步状态机. 根据状态机的输出信号是否与电路的输入有关分为 Meal ...

  8. TEA5676 + AT24C08 FM收音机 搜台 存台 mmap 实现读写

    硬件说明TEA5767 + AT24c08 要使用耳机收听,不加功放芯片,声音非常小. 这2个芯片都支持 3.3 或 5.0 电源支持连线比较简单,sda scl 接到 2440 对应的 排针上,找出 ...

  9. 自动控制理论的MATLAB仿真实例(一)

    拉普拉斯变换及其反变换 Laplace变换及其反变换的定义为:

  10. Ajax的封装,以及利用jquery的ajax获取天气预报

    1.Ajax的封装 function ajax(type,url,param,sync,datetype,callback){//第一个参数是获取数据的类型,第二个参数是传入open的url,第三个是 ...