把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【CF1000C】Covered Points Count(离散化+差分)

点此看题面

大致题意: 给出\(n\)条线段,分别求有多少点被覆盖\(1\)次、\(2\)次...\(n\)次。

正常的算法

好吧,这道题目确实有个很简单的贪心做法(只可惜我做的时候没有想到,结果想了半天只想出一个无比麻烦的),这里介绍一个稍微有些复杂的。

不正常的算法(我的算法)

考虑离散化每一个出现过的点以及这些点后面的点(之所以要离散化这些后面的点,是为了方便后面的差分)。

假如我们用\(p[i]\)来表示原来为\(i\)的数离散化后的值,并用\(q[i]\)表示离散化后值为\(i\)的数原来的值,则:

对于一条线段,假设它的左端点为\(l\),右端点为\(r\),那么我们就将\(f[p[l]]\)加1,并将\(f[p[r+1]]\)减1(经典的差分套路),最后求出其前缀和,就可以求出每一块被覆盖的次数,从而将其还原计算出答案。

代码

#include<bits/stdc++.h>
#define max(x,y) (x>y?x:y)
#define min(x,y) (x<y?x:y)
#define LL long long
#define N 200000
using namespace std;
int n;
LL x[N+5],y[N+5],z[4*N+5],f[4*N+5],ans[N+5];
map<LL,LL> p,q;
LL read()
{
	LL x=0,f=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	while(ch>='0'&&ch<='9') (x*=10)+=ch-'0',ch=getchar();
	return x*=f;
}
void write(LL x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++) z[4*i-3]=x[i]=read(),z[4*i-2]=x[i]+1,z[4*i-1]=y[i]=read(),z[4*i]=y[i]+1;
	int w=4*n,k=0;
	sort(z+1,z+w+1);
	for(int i=1;i<=w;i++) if(z[i]!=z[i-1]||i==1) p[z[i]]=i-k,q[i-k]=z[i];else k++;//离散化
	for(int i=1;i<=n;i++) f[p[x[i]]]++,f[p[y[i]]+1]--;//差分
	for(int i=1;i<w;i++) ans[f[i]+=f[i-1]]+=q[i+1]-q[i];//前缀和累加,然后还原计算答案
	for(int i=1;i<=n;i++) write(ans[i]),putchar(' ');
	return 0;
}
posted @ 2018-10-29 15:39  TheLostWeak  阅读(238)  评论(0编辑  收藏  举报