【二分 树状数组】North America Championship 2020 G.ICPC Camp
2021-08-20 19:14:00
# ACM
题链
题目解析 设题给的两个数组为 $a,b$,二分答案,相当于对每一个 $a_i$ 能在 $b$ 数组中选择的值加了限制,将 $a,b$ 数组排序之后,对于每一个 $a_i$ 在 $b$ 数组中能选择的范围就是一个区间了;
所以解决一个子问题,有 $n$ 个区间 $[l,r]$,每个区间需要选择一个数字,全部选择完后最多能有多少个不重复的数字;
对于 $n$ 个区间按照右端点 $r$ 从小到大排序,若相同则对左端点 $l$ 从小到大排序,对于每一个 $r$ 都选择大于等于它对应的 $l$ 的最小的未被选过的值,也就是大于等于 $l$ 的 $mex$,若无法选择则跳过这个区间;
用二分加树状数组查找大于等于 $l$ 的 $mex$;
如何查找 在 $[l,r]$ 中二分一个 $mid$,查找 $[l,mid]$ 中有多少个被选择的值,若小于区间长度则 $mex$ 在 $[l,mid]$ 内;
代码实现 复杂度 $O(nlogmlognlogn)$,$m$ 是值域…竟然跑完了;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 #include <bits/stdc++.h> using namespace std; #define LL long long #define Pair pair<LL ,LL > #define ls rt<<1 #define rs rt<<1|1 #define PI acos(-1.0) #define eps 1e-13 #define mod 998244353 #define MAXN 2e9 #define MS 200005 int n,m1,m2,l,r,h;int a[MS], b[MS];struct node { int l,r; }p[MS]; int tot;LL tr[MS<<2 ]; bool cmp (node t1,node t2) { if (t1.r == t2.r) return t1.l < t2.l; return t1.r < t2.r; } int lowbit (int x) { return x&(-x); } void add (int pos,int val) { for (;pos<MS;pos+=lowbit (pos)) tr[pos] += val; } LL query (int pos) { LL ans = 0 ; for (;pos;pos-=lowbit (pos)) ans += tr[pos]; return ans; } int cal () { int cnt = 0 ; for (int i=1 ;i<=m1;i++){ int tl = p[i].l; int tr = p[i].r; int t = -1 ; while (tl <= tr){ int m = tl+tr>>1 ; if (query (m) - query (p[i].l-1 ) < m-p[i].l+1 ){ t = m; tr = m-1 ; } else tl = m+1 ; } if (t != -1 ){ cnt++; add (t,1 ); } } return cnt; } int jdg (int x) { for (int i=1 ;i<=m1;i++){ if (h-a[i] < a[i]-x){ p[i] = {0 ,-1 }; continue ; } int L = min (a[i]-x,h-a[i]); int R = min (a[i]+x,h-a[i]); p[i].l = lower_bound (b+1 ,b+m2+1 ,L) - b; p[i].r = upper_bound (b+1 ,b+m2+1 ,R) - b - 1 ; } sort (p+1 ,p+m1+1 ,cmp); memset (tr,0 ,sizeof tr); int cc = cal (); return cc >= n; } inline void solve () { cin >> n >> m1 >> m2 >> h; r = h; for (int i=1 ;i<=m1;i++) cin >> a[i]; for (int i=1 ;i<=m2;i++) cin >> b[i]; sort (a+1 ,a+m1+1 ); sort (b+1 ,b+m2+1 ); int ans = -1 ; while (l <= r){ int mid = l+r>>1 ; if (jdg (mid)){ ans = mid; r = mid-1 ; } else l = mid+1 ; } cout << ans << "\n" ; } int main () { ios::sync_with_stdio (false ); int ce = 1 ; while (ce--) solve (); return 0 ; }
2021-08-20 19:14:00
# ACM