【題解】 AtCoder ARC 076 F - Exhausted? (霍爾定理+線段樹)
阿新 • • 發佈:2018-08-23
r+ uil mat amp con pan com cnblogs 找出最大值
題面
題目大意:
給你\(m\)張椅子,排成一行,告訴你\(n\)個人,每個人可以坐的座位為\([1,l]\bigcup[r,m]\),為了讓所有人坐下,問至少還要加多少張椅子。
Solution:
- 為什麽加椅子?我們可以在最左邊或最右邊一直加直到人人都有座位。
- 首先這道題目抽象成二分圖很簡單,然後我們可以只要求解出人與座位的最大匹配是多少,總人數減去即可,但跑二分圖最大匹配顯然會超時,我們就可以往霍爾定理方面想。
- 然後你還需要知道一個霍爾定理推論:假設某個人的集合為\(X\),這個集合所對應的椅子的集合為\(Y\),如果\(|X|\leq|Y|\),則具有完美匹配,如果\(|X|\geq|Y|\)
在這題裏,這個就是至少需要添加的椅子數目,所以我們要找出最大的\(\Gamma(X)\)
- 接下來我們就來分析怎麽找出最大的\(\Gamma(X)\),因為\(X\)不具有任何性質,不好下手,我們考慮\(Y\)有啥特點,他一定是\([1,l]\bigcup[r,m]\),然後我們可以通過這個\(Y\)確定\(|X|\),所以會有一下做法
法一:暴力枚舉
- 暴力枚舉\(l,r\),椅子的個數為\(l+m-r+1\),通過上面的定理處理出答案,找出\(\Gamma\)
貌似會更高到三方
法二:與其說是法二不如說是法一優化
- 我們考慮上面的算法哪一些地方是冗余的。假設我們枚舉出\(l\),根據法一,我們會枚舉出所有的\(r\),顯然不用枚舉所有的,實際上只有找出這個\(l\)對應後面的\(r\)算出來的最大值,如何快速查詢出最大值,我們考慮使用線段樹。
- 具體如何優化這個問題:計算式子是人數\(-(l+m-r+1)\)。
- 因為固定了\(l\),我們可以確定現在最多有多少人,總人數與\(l'\)有關(\(l'<l\))所以我們把\(l\)從小到大排序,把人數不斷往線段樹裏面丟。
- 具體多少人根據\(r\)
- 如果上面你看懂了,那就很好辦了,我們會發現對於枚舉的\(r\),式子中的人數\(-m-1+r\)是一樣的,人數我們是在推進\(l\)同時加入線段樹,\(-m-1+r\)我們就可以提前加入線段樹(建樹)
- 對於一種特殊的情況,比如說:\(l_i=1,r_i=1\),那麽他能放的範圍為所有,所以我們要判斷\(m-n\)為答案的情況
- 對於普通枚舉\(l\),我們沒必要考慮全部集合情況,所以我們就只用在線段樹\(l+2\rightarrow m+1\)找出最大值減去\(l\),得到的答案與\(ans\)取\(max\)就\(ok\)啦
- 下面我們來將
亂搞做法,我們把人按\(l\)排序,枚舉到人後把他可以座椅子的範圍用線段樹標記,然後算出總可以坐的椅子數與人數相比較,求出每次\(ans\)的\(max\),一開始錯兩個點,然後排了兩個序,算兩次就只錯一個點了。這個方法顯然是不對噠!!因為顯然有一些人的子集沒有枚舉到。
這道題好理解吧(毛線,我起碼看了一個下午才看懂,去吃飯的路上突然懂了23333)
對了貪心也可以過這道題,只不過做法沒這麽優美罷了
Attention:
- 線段樹是從\(0\rightarrow m+1\),因為人的\(l,r\)包含\(0,m+1\)
- 特殊情況,\(|X|=n\)
枚舉出\(l\)後,找最大值一定是從\([l+1,m+1]\)中找
First, 你枚舉的\(r\)要\(>l\)。
Second,\(|X|=n\)已經被考慮(沒那個必要了,其實你從\(l+1\)開始也不影響)
Code:
//It is coded by ning_mew on 7.16
#include<bits/stdc++.h>
#define ls(x) (x*2)
#define rs(x) (x*2+1)
using namespace std;
const int maxn=2e5+7,inf=1e9+7;
int n,m,ans=0;
struct Opt{int l,r;}p[maxn];
struct Node{int lazy,maxx;}node[maxn*4];
bool cmp(const Opt &A,const Opt &B){return A.l<B.l;}
void pushdown(int num,int nl,int nr){
if(!node[num].lazy)return;
int lz=node[num].lazy; node[num].lazy=0;
node[ls(num)].maxx+=lz;node[ls(num)].lazy+=lz;
node[rs(num)].maxx+=lz;node[rs(num)].lazy+=lz;
}
void update(int num){node[num].maxx=max(node[ls(num)].maxx,node[rs(num)].maxx);}
void build(int num,int nl,int nr){
node[num].lazy=0; if(nl==nr){node[num].maxx=nr-m-1;return;}
int mid=(nl+nr)/2;
build(ls(num),nl,mid);build(rs(num),mid+1,nr);
update(num);
}
void add(int num,int nl,int nr,int ql,int qr,int ad){
if(ql<=nl&&nr<=qr){node[num].maxx+=ad;node[num].lazy+=ad;return;}
if(nr<ql||qr<nl)return;
int mid=(nl+nr)/2;pushdown(num,nl,nr);
add(ls(num),nl,mid,ql,qr,ad);add(rs(num),mid+1,nr,ql,qr,ad);
update(num);return;
}
int quary(int num,int nl,int nr,int ql,int qr){
if(ql<=nl&&nr<=qr)return node[num].maxx;
if(nr<ql||qr<nl)return -inf;
int mid=(nl+nr)/2;pushdown(num,nl,nr);
return max(quary(ls(num),nl,mid,ql,qr),quary(rs(num),mid+1,nr,ql,qr));
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d%d",&p[i].l,&p[i].r);
sort(p+1,p+n+1,cmp);p[n+1].l=inf;
build(1,0,m+1);
for(int i=1;i<=n;i++){
add(1,0,m+1,0,p[i].r,1);
if(p[i].l!=p[i+1].l&&p[i].l<=m-1)ans=max(ans,quary(1,0,m+1,p[i].l+2,m+1)-p[i].l);
}ans=max(ans,n-m);printf("%d\n",ans);
return 0;
}
博主蒟蒻,隨意轉載。但必須附上原文鏈接:http://www.cnblogs.com/Ning-Mew/,否則你會場場比賽暴0!!!
【題解】 AtCoder ARC 076 F - Exhausted? (霍爾定理+線段樹)