在洛谷上搜线段树的题,就找到了这个,就用线段树的模板写一下。
题目链接:挤牛奶Milking Cows - 洛谷
由于题目中l
、r
的范围只有1e6,因此可以用线段树进行维护
线段树中每个线段表示该区间内有多少人在工作,比如题目的样例
3
300 1000
700 1200
1500 2100
其中线段[300,1000]上每个位置都是1,那么query(300,1000)
得到的结果是700+1,因为两端都包含了,所以只需要对l,r进行更新即可
使用二分进行答案的查找,对每个答案进行判断是否可行
判断第一个的时候要与x+1进行比较,因为两端都包含,判断第二个要让最后的结果+2,因为两端都不包含:
比如:[1,4]、[6,8],其中最长的是【1,4】共5
个贡献,没有工作的则是1
判断的范围要在题目所给的lr之间
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
const int N = 2e6+10;
int tree[N * 4];
int a[N],tag[N*4];
inline int ls(int p){return p<<1ll;}
inline int rs(int p){return p<<1ll|1ll;}
// 从下向上传递区间值
void push_up(int p){
tree[p] = tree[ls(p)] + tree[rs(p)];//区间和
// tree[p] = max(tree[ls(p)],tree[rs(p)]);//最值
}
// 建树
void build(int p,int pl,int pr){
tag[p]=0;
if(pl==pr){
tree[p] = a[pl];
return;
}
int mid = (pl + pr) / 2;
build(ls(p),pl,mid);//递归左儿子
build(rs(p),mid+1,pr);//递归右儿子
push_up(p);// 从下往上传递区间值
}
void addtag(int p,int pl,int pr,int d){
tag[p] = d;
tree[p] = d*(pr-pl+1);
}
void push_down(int p,int pl,int pr){
if(tag[p] != 0){
int mid = (pl + pr) / 2;
addtag(ls(p),pl,mid,tag[p]);
addtag(rs(p),mid+1,pr,tag[p]);
tag[p] = 0;
}
}
void update(int L,int R,int p,int pl,int pr,int d){
if (L <= pl && pr <= R){
addtag(p,pl,pr,d);
return;
}
push_down(p,pl,pr);
int mid = (pl + pr) / 2;
if(L <= mid) update(L,R,ls(p),pl,mid,d);
if(R > mid) update(L,R,rs(p),mid+1,pr,d);
push_up(p);
}
// 查询 [L,R]区间的区间和,递归到节点p,该节点的范围是[pl,pr]
int query(int L,int R,int p,int pl,int pr){
if(L <= pl && R >= pr){ //完全覆盖
return tree[p];
}
push_down(p,pl,pr);
int mid = (pl + pr) / 2;
int res = 0;
if(L <= mid) res += query(L,R,ls(p),pl,mid); //L与左儿子有重叠
if(R > mid) res += query(L,R,rs(p),mid+1,pr); //R与有儿子有重叠
return res;
// 调用方式:query(L,R,1,1,n,d);//即从根节点1开始查询,改节点的范围是[1,n],查询范围[L,R]
}
int maxn = 2e6;
int lc = maxn,rc = 0;
int n;
bool check1(int x){
for(int i = lc ; i + x <= rc ; i ++){
if(query(i,i+x,1,1,maxn) == x+1)return true;
}
return false;
}
bool check2(int x){
for(int i = lc ; i + x <= rc ; i ++){
if(query(i,i+x,1,1,maxn) == 0) {
return true;
}
}
return false;
}
void solve(){
cin >> n;
int x,y;
for(int i = 1 ; i <= n ; i ++){
cin >> x >> y;
x++,y++;
lc = min(lc,x);
rc = max(rc,y);
update(x,y,1,1,maxn,1);
}
int l = 0,r = 1e6+10;
int ans1 = 0;
int ans2 = 0;
while(l <= r){
int mid = l + r >> 1;
if(check1(mid)){
ans1 = max(ans1,mid);
l = mid + 1;
}else{
r = mid - 1;
}
}
l = 0,r = 2e6+10;
while(l <= r){
int mid = l + r >> 1;
if(check2(mid)){
ans2 = max(ans2,mid);
l = mid + 1;
}else{
r = mid - 1;
}
}
cout<<ans1<<' '<<(ans2 == 0 ? 0 : ans2+2)<<'\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t = 1;
while(t--){
solve();
}
}