Codeforces 1034D Intervals of Intervals

题目
二分被选中的区间价值的最小值 M M M
考虑求出对于每个 R R R最大的 L L L使得 [ L , R ] [L,R] [L,R]的价值 ≥ M \geq M M
发现这个最大的 L L L R R R递增而单调递增。
所以就在移动最大的 L L L R R R的时候同时维护 [ L , R ] [L,R] [L,R]的价值即可。
R − 1 → R R -1\rightarrow R R1R的时候,把R的区间插入ODT(珂朵莉树),那么就会总共出现 O ( n ) O(n) O(n) [ a , b ] [a,b] [a,b]区间的最后覆盖时间从 x → y x\rightarrow y xy的修改,那么 [ L , R ] [L,R] [L,R]的答案就是最后覆盖时间在 [ L , R ] [L,R] [L,R]也可以说 ≥ L \geq L L的线段总长。
这个可以通过用差分数组维护之前所提到的 O ( n ) O(n) O(n)个修改而得到 [ L , R ] [L,R] [L,R]的值。
可以先ODT把 O ( n ) O(n) O(n)个修改预处理求出再二分答案。
时间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)
A C   C o d e \rm AC \ Code AC Code

#include<bits/stdc++.h>
#define maxn 300005
#define LL long long
using namespace std;

int n;
int K;

//ODT
struct node{
	int l,r;
	mutable int t;
	node(int l=0,int r=0,int t=0):l(l),r(r),t(t){}
	bool operator <(const node &B)const{ return l<B.l; }
};
#define IT set<node>::iterator 
set<node>Tr;

IT split(int pos){// cut between pos-1 and pos
	IT u=Tr.lower_bound(pos);
	if(u!=Tr.end() && (*u).l == pos) return u;
	u--;
	if((*u).r == pos) return Tr.end();
	node t = *u;
	Tr.erase(u);
	Tr.insert(node(t.l,pos,t.t));
	return Tr.insert(node(pos,t.r,t.t)).first;
}

vector<pair<int,int> >G[maxn];
int ad[maxn];
pair<LL,LL> chk(int mid){
	pair<LL,LL>ret;
	LL sm=0;int L=0,val=0;
	for(int i=1;i<=n;i++){
		for(int j=0;j<G[i].size();j++){
			if(G[i][j].first > L)
				ad[G[i][j].first] += G[i][j].second;
			else 
				val += G[i][j].second,
				sm += G[i][j].second * (L-G[i][j].first+1ll);
			ad[i+1] -= G[i][j].second;
		}
		for(;L+1<=i && val+ad[L+1] >= mid;L++)
			val+=ad[L+1],sm+=val;
		ret.first += L , ret.second += sm;
	}
	for(int i=1;i<=n;i++) ad[i] = 0;
	return ret;
}

int main(){
	scanf("%d%d",&n,&K);
	Tr.insert(node(1,1e9));
	for(int i=1,a,b;i<=n;i++){
		scanf("%d%d",&a,&b);
		IT r=split(b),l=split(a);
		for(;l!=r;){
			node t=*l;
			Tr.erase(l++);
			G[i].push_back(make_pair(t.t+1,t.r-t.l));
		}
		Tr.insert(node(a,b,i));
	}
	int L=1,R=1e9,mid;
	for(;L<R;){
		mid = L+R+1 >> 1;
		pair<LL,LL> t = chk(mid);
		if(t.first >= K) L = mid;
		else R = mid - 1;
	}
	pair<LL,LL> ans = chk(L);
	printf("%lld\n",ans.second - (ans.first - K) * L);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值