小明最近非常喜欢区间,于是他想出来这样一个问题:
给定平行于x轴的 n 条线段。每个线段的左右端点坐标都是整数。有些线段可以退化成点。线段之间可以相互交叉,嵌套,甚至重合。
这样所有 x 轴上的整数点最少被 0 条线段覆盖,最多同时被 n 条线段覆盖。
你的任务是:求出 x 轴上,分别被 条线段覆盖的,坐标为整数的点的数量。()。
注意:被线段的左右端点覆盖也算是覆盖。
输出共 n 个数,第 1 个数表示被 1 条线段覆盖的整点数量,第 2 个数表示被2线段覆盖的整点数量......
输入的第一行包含一个整数n(1≤n≤2*10^5)—线段的数量。 接下来的n行。 第i行包含一对整数li,ri(0≤li≤ri≤10^18),表示第i段的端点。
输出包括一行n个数字,第i个数字表示被i条线段覆盖的点的数目。
对于10%的数据,1<= n <= 8 对于50%的数据,1 <= n<= 1024 对于100%的数据,1 <= n <= 200000 0≤li≤ri≤10^18。
3 0 3 1 3 3 8
6 2 1
解析:
我们知道,每一个区间的贡献是1,那么我便可以在区间的左端点加1,右端点减1,这样可以累加过去,便可以实现这个区间的每一个数字加1,对每一个区间都这样操作,我们不用遍历每一个数字,对区间的端点从小到大排序,对于排序后的端点,我们可以O(1)计算出这个区间的有多少个数字有着相同的贡献,贡献的数值直接累加端点值即可,具体看代码,时间复杂度O(nlogn)。
放代码:
#include <bits/stdc++.h> #define N 200010 #define ll long long using namespace std; int n,ans[N]; struct node { ll pos; int id;//id==0?l:r bool operator < (const node &t) { return pos<t.pos; } }p[N<<1]; int main() { ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;i++) { cin>>p[i*2-1].pos>>p[i*2].pos; p[i*2].pos++,p[i*2].id=1; } sort(p+1,p+1+2*n); p[0]=p[1]; for(int i=1,cnt=0;i<=2*n;i++) { ans[cnt]+=p[i].pos-p[i-1].pos; if(!p[i].id)cnt++; else cnt--; } for(int i=1;i<=n;i++)cout<<ans[i]<<" \n"[i==n]; return 0; }