https://ac.nowcoder.com/acm/contest/13175/C
数轴上有[1,n]一共n个点,m个区间分别是[li,ri]。
设tot为所选取的区间数量,x为所有所选取的区间的交集长度。
求min(tot,x)的最大值。
尺取法
题意即是尽可能多的段同时重复段尽量长
所选的区间左端点一定是某区间的左端点
所取的区间右端点也是
先按左端点排序区间,让所选的个数小于等于交集的长度,
如果大了就去掉最前面的区间
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 3e5 + 7; pair<int,int> a[N]; int n,m; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) scanf("%d%d",&a[i].first,&a[i].second); sort(a+1,a+1+m); ll ans=0,cnt=0; priority_queue<int, vector<int>, greater<int> > q; for(int i=1;i<=m;++i){ q.push(a[i].second); ++cnt; while(cnt>q.top()-a[i].first+1){ q.pop(); --cnt; } ans=max(ans,cnt); // cout<<"==="<<cnt<<" "; } cout<<ans<<" "; return 0; }
二分答案
nlognlogn+mlogm
#include <bits/stdc++.h> #define sc(x) scanf("%d", &(x)) #define pr(x) printf("%d ", (x)) using namespace std; typedef pair<int, int> pii; const int N = 3e5 + 7; #define lowbit(x) ((x) & (-x)) int tree[N]; inline void add(int i) { for (int pos = i; pos < N; pos += lowbit(pos)) ++tree[pos]; } inline int query(int n) { int ans = 0; for (int pos = n; pos; pos -= lowbit(pos)) ans += tree[pos]; return ans; } pii a[N]; int main() { int n, m; sc(n), sc(m); for (int i = 0; i < m; ++i) sc(a[i].first), sc(a[i].second); sort(a, a + m); int ans = 0; for (int L = 1, p = 0; L <= n; ++L) { while (p < m && a[p].first <= L) add(a[p++].second); int left = L, right = n, R = 0; while (left <= right) { int mid = left + right >> 1;//选取区间的右端点 int tot = p - query(mid - 1);//减去不满足我们枚举出的交集的点 if (tot >= mid - L + 1)//尝试扩大区间 left = mid + 1, R = mid; else right = mid - 1; } ans = max(ans, R - L + 1); } pr(ans); return 0; }