CodeForces - 1034D Intervals of Intervals
阿新 • • 發佈:2021-07-14
我是^(* ̄(oo) ̄)^!耶!
目錄
,則計算第 \(r\) 個時間對應的線段。那麼 \(\le r\) 的條件一定滿足,於是定義 \(f(i)\) 為時間戳 \(\ge i\) 的線段並長度。思考一下線段 \([L,R]\) 的時間戳從 \(t\) 變到 \(t'\) 會有什麼影響:對於 \(i\in [t+1,t']\) 的 \(f(i)\) 都加上了 \(R-L\)。這個可以差分一下。
的區間的個數與權值和。需要注意的是可能有多個權值為第 \(k\) 大的區間,但由於已經知道這些區間的權值與個數,減去即可。另:如果查詢權值 \(>\rm mid\) 的區間的話,\(k-1\) 可能等於 \(0\),二分就會不停往大分。
博主的 \(\rm bibi\) 時間
“不會還有人不知道區間 \([l,r]\) 的長度是 \(r-l\) 吧?”
題目
解法
還是來理一理思路吧。
先考慮弱化版:詢問在 \([l,r]\) 中線段的並的長度。
按 \(1\) 到 \(n\) 的順序加入線段,用 set
來維護。需要維護三個值 \((l,r,t)\),其中 \(l,r\) 是線段端點,\(t\) 是 最新 覆蓋此區間的編號。需要注意的是,當 \(t\) 相等時必須保證線段不相交。
有什麼用呢?實際上我們預先按順序加入線段,用 vector
儲存每個時間包含的線段(還需要儲存上一個時間戳)。將詢問按右端點排序,假設當前詢問為 \([l,r]\)
如果強制線上呢?將差分陣列改成線段樹,再可持久化一下即可。
回到這道題,我們要求前 \(k\) 大區間的權值和(權值定義為線段的並的長度)。可以考慮二分第 \(k\) 大區間的權值,設當前二分到 \(\rm mid\),那麼問題轉化為查詢權值 \(\ge \rm mid\)
在檢驗函式中,你會發現大區間的權值一定比它包含的小區間的權值大。基於此就可以用 \(\text{two-pointers}\) 查詢權值 \(\ge \rm mid\) 的區間:\(r\) 右移,計算第 \(r\) 個時間對應的線段。維護 \(l\) 為此情況下權值 \(\ge \rm mid\) 的最大左端時間,那麼 \([1,l]\) 都是合法的。
還有一些細節,程式碼加了註釋。
程式碼
#include <bits/stdc++.h>
using namespace std;
#define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y)
#define debug(...) do {cerr<<__LINE__<<" : ("#__VA_ARGS__<<") = "; Out(__VA_ARGS__); cerr<<flush;} while(0)
template <typename T> void Out(T x) {cerr<<x<<"\n";}
template <typename T,typename ...I> void Out(T x,I ...NEXT) {cerr<<x<<", "; Out(NEXT...);}
template <class T> inline T read(const T sample) {
T x=0; int f=1; char s;
while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
template <class T> inline void write(const T x) {
if(x<0) return (void) (putchar('-'),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
typedef long long ll;
typedef pair <ll,ll> pii;
#define int long long
const int maxn=3e5+5;
int n,m;
ll add[maxn];
struct node {
int l,r,t;
bool operator < (const node fk) const {
return l<fk.l;
}
};
set <node> s;
vector <pii> g[maxn];
typedef set <node> :: iterator Type;
Type split(int x) {
Type it=s.lower_bound((node){x,0,0});
if(s.end()!=it and it->l==x) return it;
--it;
if(it==s.end() or it->r==x) return s.end();
node tmp=*it;
s.erase(it);
s.insert((node){tmp.l,x,tmp.t});
return s.insert((node){x,tmp.r,tmp.t}).first;
}
pii ask(int x) {
pii tt,ret; int L=0;
ll sum=0,tmp=0;
rep(i,1,n) add[i]=0;
rep(i,1,n) {
for(int j=0;j<g[i].size();++j) {
tt=g[i][j];
/*
當 L>=tt.first 則 [tt.first,L] 一定滿足條件,先加入 sum,為避免重複不加入差分陣列
*/
if(tt.first>L)
add[tt.first]+=tt.second;
else {
tmp+=tt.second;
sum+=1ll*tt.second*(0ll+L-tt.first+1);
}
add[i+1]-=tt.second;
}
while(L+1<=i and tmp+add[L+1]>=x) {
tmp+=add[L+1];
sum+=tmp; ++L;
}
ret.first+=L,ret.second+=sum;
}
return ret;
}
signed main() {
n=read(9),m=read(9);
s.insert((node){0,(int)1e9,0});
rep(i,1,n) {
int a=read(9),b=read(9);
Type L=split(a),R=split(b);
while(L!=R) {
g[i].push_back(make_pair(L->t+1,L->r-L->l));
s.erase(L++);
}
s.insert((node){a,b,i});
}
int l=0,r=1e9,mid; pii ret;
while(l<r) {
mid=l+r+1>>1;
ret=ask(mid);
if(ret.first>=m) l=mid;
else r=mid-1;
}
ret=ask(l);
print(ret.second-1ll*(ret.first-m)*l,'\n');
return 0;
}