队爷的新书
问题描述
队爷即将出版新书,以记录他辉煌的虐题生涯。。。
有 n 家出版社对这本书表示了兴趣,并愿意给队爷支付 p∈[Min_pay,Max_pay]的报酬来得到这本书的出版权,每家出版社的Min_pay 和 Max_pay 是不一样的。
现在队爷希望你帮他找出一个报酬值 p,使得他获得的总报酬最多。(每一个 Min_pay<=p<=Max_pay 的出版社都会付给队爷 p的报酬)
输入文件
第一行为一个整数 n。
接下来 n 行每行 2 个整数 Min_payi 和 Max_payi,为第 i 家出版社愿支付的报酬范围。
输出文件
只有一个整数 ans,为最大总报酬。
3
输入样例
4
1 3
2 4
3 5
4 7
输出样例
12
样例解释
当 p=4 时,有 3 家出版社会给出报酬,此时最大。
数据规模与约定
对于 20%的数据,1<= Min_pay,Max_pay<=10000;
对于 40%的数据,1<=n<=1000,1<= Min_pay,Max_pay<=10^6;
对于 100%的数据,1<=n<=100000,1<= Min_pay,Max_pay<=10^9。
分析
因为这是闭区间,最后的答案一定在区间端点上,其实这个和刘汝佳书上的扫描线法很像,把左右端点看成一个事件,只有遇到端点时,答案才会变化,由于这个是闭区间所以遇到端点答案是会增加的,所以两个端点(不一定非得是左右端点)之间的点一定没有端点优。其实可以换一个思路想,其实每个区间都会给区间的每一个点的权值增加1,由于是单点查询,所以就可以用差分维护。但max_pay太大了,就可以对区间左右的端点离散化之后差分。
代码
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=200010; inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,t[N],tot,s[N]; long long ans; struct node{ int x,y; }a[N],b[N]; int main(){ n=read(); for(int i=1;i<=n;++i){ a[i].x=read();a[i].y=read(); t[++tot]=a[i].x; t[++tot]=a[i].y; } sort(t+1,t+2*n+1); int m=unique(t+1,t+2*n+1)-(t+1); for(int i=1;i<=n;++i){ b[i].x=lower_bound(t+1,t+m+1,a[i].x)-t; b[i].y=lower_bound(t+1,t+m+1,a[i].y)-t; } for(int i=1;i<=n;++i) ++s[b[i].x],--s[b[i].y+1]; for(int i=1;i<=m;++i) s[i]+=s[i-1]; for(int i=1;i<=m;++i) if(s[i]*1ll*t[i]>ans) ans=s[i]*1ll*t[i]; printf("%lld ",ans); return 0; }