[离散化+树状数组]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对寿 ...
随机推荐
- mysql 分表实现方法详解
如果你需要进行mysql分表了我们就证明你数据库比较大了,就是把一张表分成N多个小表,分表后,单表的并发能力提高了,磁盘I/O性能也提高了.并发能力为什么提高了呢,因为查寻一次所花的时间变短了,如果出 ...
- 谈谈Vue的递归组件
2月最后一天,而且还四年一遇,然而本月居然一篇博客没写,有点说不过去.所以,今天就来谈谈Vue的递归组件.我们先来看一个例子: See the Pen 递归组件 by imgss (@imgss) o ...
- 记 MySQL优化 20条
1. 为查询缓存优化你的查询 大多数的MySQL服务器都开启了查询缓存.这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的.当有很多相同的查询被执行了多次的时候,这些查询结果会被放到一 ...
- c++背包问题
又鸽了好久…… 前言 博主刚刚学会背包问题不久,然后有一段时间没练习了 今天就来重新温习一下,顺手就写了这一篇博客. 好了,下面进入正题! 算法简介 背包问题是动态规划的一个分支 主要是分成了01背包 ...
- 达拉草201771010105《面向对象程序设计(java)》第六周学习总结
达拉草201771010105<面向对象程序设计(java)>第六周学习总结 第一部分:理论知识 1.类.超类和子类 类继承的格式: class 新类名extends已有类名一般来说,子类 ...
- iOS 使用系统的UITabBarController 修改展示的图片大小
1. 设置TabBarItem图片的大小 1 - (void)configurationAppTabBarAndNavigationBar { // 选中的item普通状态图片的大小 UIImage ...
- 深度解析互联网大厂面试难题自定义@EnableXX系列
深度解析互联网大厂面试难题自定义@EnableXX系列 其实是一个@Import的设计技巧 创建注解@EnableXX(任何名称注解都行,只是这个名字好一些) XXConfiguration类不能 ...
- 从头认识js-js客户端检测
常用的客户端检测方式有以下三种: 1.能力检测 2.怪癖检测 3.用户代理检测 能力检测 最常用也是最为人们广泛接受的客户端检测形式是能力检测(又称特性检测).能力检测的目标不是识别特定的浏览器,而是 ...
- python安装pip (windows64)
1.前提条件是先安装了easy_install(easy_install安装教程http://www.cnblogs.com/IT-Crowd/articles/6528469.html) 2.在ea ...
- vue_相同组件,不同url跳转不重新渲染的解决方法
最近写的这个项目,有很多下拉菜单,每个菜单会有相应的两种类型.现在产品的需求是,跳转到不同的类型 需要页面重新渲染数据 那么问题来了. 我试了好几种方法,用watch监听路由去判断,但是发现输在inp ...