题目
二分被选中的区间价值的最小值
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
R−1→R的时候,把R的区间插入ODT(珂朵莉树),那么就会总共出现
O
(
n
)
O(n)
O(n)次
[
a
,
b
]
[a,b]
[a,b]区间的最后覆盖时间从
x
→
y
x\rightarrow y
x→y的修改,那么
[
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);
}