想到这道题的解法是建个数组,每读入一条线段进来,就把这线段上的每个点+1,最后扫一遍数组算出count数组,这么做的复杂度是n*max(a[i]);简单用前缀和优化,复杂度变为n+max(a[i])还是过不了。我们想到a[i]是10^18级别的,而n最大200000,所以可以想象出这个前缀和数组里面大多数都是0(有很多是零的连续区间),然后每个0的连续区间维护出来的前缀和都是一样的【很多的计算力耗费在这个上面了】,所以我们想到只考虑不是0的地方,然后新的不是0的地方和上一个不是0的地方之间的点被线段覆盖次数是一样的。不是0的地方有n级别个,由于我们用map维护(要把所有端点从左到右排序),所以O(nlogn)复杂度。
map的遍历看代码
#include<iostream> #include<map> using namespace std; map<long long,int> m; long long count[200005]; int main(){ int n; cin>>n; for(int i=1;i<=n;i++){ long long start,end; scanf("%lld%lld",&start,&end); m[start]++; m[end+1]--; } long long last=0; int cnt=0; //考虑每个区间 for( map<long long,int>::iterator it = m.begin(); it!=m.end(); it++){ if( it==m.begin() ) { last=it->first; cnt+=it->second; continue; } count[ cnt ] += it->first - last; last=it->first; cnt+=it->second; } for(int i=1;i<=n;i++) cout<<count[i]<<" "; return 0; }