离散化的本质,是映射,将间隔很大的点,映射到相邻的数组元素中。减少对空间的需求,也减少计算量。
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
输入格式
第一行包含两个整数 n 和 m。
接下来 n行,每行包含两个整数 x 和 c。
再接下来 m 行,每行包含两个整数 l 和 r。
输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。
数据范围
−1e9≤x≤1e9,
1≤n,m≤1e5,
−1e9≤l≤r≤1e9,
−10000≤c≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
1.读输入。将每次读入的x c push_back()到add中,将每次读入的位置x push_back()到alls中,将每次读入的l r push_back()到query中。
cin>>n>>m;
for(int i=0;i{
int x,c;
cin>>x>>c;
add.push_back({x,c});
alls.push_back(x);
}
for(int i=0;i{
int l,r;
cin>>l>>r;
query.push_back({l,r});
alls.push_back(l);
alls.push_back(r);
}
2.排序、去重。
//去重
//对all数组中的元素进行排序并删除重复元素
sort(alls.begin(),alls.end());
//unique函数将alls数组中不重复的元素放在前面,重复的元素放到后面,并返回第一个重复元素的地址
alls.erase(unique(alls.begin(),alls.end()),alls.end());
3.通过遍历add,完成在离散化的数组映射到的a数组中进行加上c的操作(用到find函数)。
for(auto item : add)
{
int x=find(item.first);
a[x]+=item.second;
}
int find(int x)//利用二分方法查找x在alls中的下标+1
{
int l=0,r=alls.size()-1;
while(l{
int mid=l+r>>1;
if(alls[mid]>=x) r=mid;
else l=mid+1;
}
return r+1;//为方便利用前缀和返回r+1
}
4.初始化s数组(前缀和)
for(int i=1;i<=alls.size();i++)
s[i]=s[i-1]+a[i];
5.通过遍历query,完成求区间[l,r]的和。
for(auto item : query)
{
int l=find(item.first),r=find(item.second);
cout<}
#include
#include
#include
using namespace std;
typedef pairPII;
vectoralls;
vectoradd,query;
const int N=3e5+10;
int a[N],s[N];
int m,n;
int find(int x)//利用二分方法查找x在alls中的下标+1
{
int l=0,r=alls.size()-1;
while(l>1;
if(alls[mid]>=x) r=mid;
else l=mid+1;
}
return r+1;//为方便利用前缀和返回r+1
}
int main()
{
cin>>n>>m;
for(int i=0;i>x>>c;
add.push_back({x,c});
alls.push_back(x);
}
for(int i=0;i>l>>r;
query.push_back({l,r});
alls.push_back(l);
alls.push_back(r);
}
//去重
//对all数组中的元素进行排序并删除重复元素
sort(alls.begin(),alls.end());
//unique函数将alls数组中不重复的元素放在前面,重复的元素放到后面,并返回第一个重复元素的地址
alls.erase(unique(alls.begin(),alls.end()),alls.end());
//插入
for(auto item : add)
{
int x=find(item.first);
a[x]+=item.second;
}
//前缀和
for(int i=1;i<=alls.size();i++) s[i]=s[i-1]+a[i];
for(auto item : query)
{
int l=find(item.first),r=find(item.second);
cout<
N = 300010 #n + 2m
alls = list()
a = [0] * N
s = [0] * N
add = [[0] * 2 for i in range(N)]
query = [[0] * 2 for i in range(N)]
size = 0 #统计alls中的坐标个数
def quickSort(a, l, r):
if(l >= r):
return
x, i, j = a[l + r >> 1], l - 1, r + 1
while(i < j):
while(True):
i += 1
if(a[i] >= x): break
while(True):
j -= 1
if(a[j] <= x): break
if(i < j):
tmp = a[i]
a[i] = a[j]
a[j] = tmp
quickSort(a, l, j)
quickSort(a, j + 1, r)
def unique(a):
global size
i, j = 0, 0
while(i < size):
if(i == 0 or a[i] != a[i - 1]):
a[j] = a[i]
j += 1
i += 1
size = j
def find(x):
global alls
l, r = 0, size - 1
while(l < r):
mid = l + r >> 1
if(alls[mid] >= x): r = mid
else: l = mid + 1
return r + 1
def main():
global alls, a, s, add, query, size
n, m = list(map(int, input().split()))
oldn, oldm = n, m
i = 0
while(oldn):
x, c = list(map(int, input().split()))
alls.append(x)
add[i][0] = x
add[i][1] = c
i += 1
oldn -= 1
i = 0
while(oldm):
l, r = list(map(int, input().split()))
alls.append(l)
alls.append(r)
query[i][0] = l
query[i][1] = r
i += 1
oldm -= 1
size = len(alls)
#排序 和 去重
quickSort(alls, 0, size - 1)
unique(alls)
alls = alls[:size]
for i in range(n):
x = add[i][0]
c = add[i][1]
index = find(x)
a[index] += c
for i in range(size):
s[i + 1] = s[i] + a[i + 1]
for i in range(m):
l = find(query[i][0]);
r = find(query[i][1]);
print(s[r] - s[l - 1])
main()
给定 n 个区间 [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如[1,3] 和 [2,6]可以合并为一个区间 [1,6]。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含两个整数 l 和 r。
输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。
数据范围
1≤n≤100000,
−1e9≤li≤ri≤1e9
输入样例:
5
1 2
2 4
5 6
7 8
7 9
输出样例:
3
1:先排序。依照左端点从小到大排序,若左端点同 则按照右端点从小到大排序
2:不断 更新 st 和 ed :现有区间的左右端点
若最新枚举到的 小区间 属于现有大区间, 则st不会改变 只需要更新 ed
若最新枚举到的 小区间 不属于现有大区间,则res++ , 同时更新 st 和 ed为最新区间的左右端点
所以本题:
首先按照左端点排序;
逐个遍历所有区间,判断当前区间能不能接到前一个区间里面:
2.1 如果没有交集,那么就将上一个区间记录到答案中,然后将当前区间作为新的区间范围。
2.2 如果有交集,能够接到上一个区间中,那么就更新区间的范围 —— 判断右端点是否需要更新。
#include
#include
#include
#include
using namespace std;
typedef pair PII;
int n;
void merge(vector &segs)
{
vector res;
// 1. 首先按照左端点排序;
sort(segs.begin(), segs.end());
// 2. 然后遍历所有区间:
int st = -2e9, ed = -2e9;
for (auto seg : segs)
{
// 2.1 如果没有交集,那么就将上一个区间记录到答案中,然后将当前区间作为新的区间范围;
if (ed < seg.first)
{
if (st != -2e9) res.push_back({st, ed});
st = seg.first, ed = seg.second;
}
// 2.2 如果有交集,能够接到上一个区间中,那么就更新区间的范围。
else
ed = max(ed, seg.second);
}
// 3. 需要将最后一个区间也加到答案中去。
if (st != -2e9)
res.push_back({st, ed});
segs = res;
}
int main()
{
cin >> n;
vector segs;
for (int i = 0; i < n; i ++ )
{
int l, r;
cin >> l >> r;
segs.push_back({l, r});
}
merge(segs);
cout << segs.size() << endl;
return 0;
}
N = int(input())
qujian_list = []
for i in range(N):
qujian_list.append(list(map(int, input().split())))
def diagnose(list_1, list_2): # list根据区间左端点排序
if list_1[-1] < list_2[0]:
return 'not inter'
if list_1[-1] >= list_2[-1]:
return 'contained'
if list_1[-1] >= list_2[0]:
return 'inter'
qujian_list.sort()
new_list = qujian_list[0]
res = 1
for i in qujian_list[1:]:
if diagnose(new_list, i) == 'not inter':
res += 1
new_list = i
if diagnose(new_list, i) == 'contain':
pass
if diagnose(new_list, i) == 'inter':
new_list = [new_list[0], i[-1]]
print(res)