1. 程式人生 > >「6月雅禮集訓 2017 Day8」infection

「6月雅禮集訓 2017 Day8」infection

div 線段 經典的 n) view sig iostream 技術 hid

【題目大意】

有$n$個人,每個人有一個初始位置$x_i$和一個速度$v_i$,你需要選擇若幹個人來感染一個傻逼病毒。

當兩個人相遇(可以是正面和背面),傻逼病毒會傳染,求經過無限大時間後,傳染完所有人的方案數。

【題解】

考慮經過無限大時間後結束的數列,一定是按$v_i$排序的。

對於第i個人,如果他帶有病毒,那麽

原來在它左邊的速度最大的點一定會超過它,到達右邊能到達的最大值,這個點會經過若幹個點,這些都會被傳染。

原來在它右邊的速度最小的點一定會跑到它的後面,到達左邊能到達的最小值,同理也會被傳染。

所以每個人的傳染是最後的一個區間,這個區間可以用線段樹或者單調隊列找出,然後就是經典的區間覆蓋問題了。

有一種非常美妙的$O(n)$的dp可以解決這個問題。

反正xjb做就可以了,具體看代碼

技術分享
# include <vector>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const int M = 2e5 + 10
; const int inf = 1.05e9; const int mod = 1e9 + 7; int n; struct pa { int x, v, ps; pa() {} pa(int x, int v, int ps) : x(x), v(v), ps(ps) {} }p[M]; inline bool cmp_pos(pa a, pa b) { return a.x < b.x; } inline bool cmp_va(pa a, pa b) { return a.v < b.v; } struct segnode {
int w, id; segnode() {} segnode(int w, int id) : w(w), id(id) {} friend bool operator < (segnode a, segnode b) { return a.w < b.w; } friend bool operator > (segnode a, segnode b) { return a.w > b.w; } }; struct SMT { # define ls (x<<1) # define rs (x<<1|1) segnode mx[M << 2], mi[M << 2]; inline void set() { for (int i=1; i<=(n<<2); ++i) mx[i] = segnode(-inf, -1); for (int i=1; i<=(n<<1); ++i) mi[i] = segnode(inf, -1); } inline void edt(int x, int l, int r, int ps, int d, int dd) { if(l == r) { mx[x] = mi[x] = segnode(d, dd); return ; } int mid = l+r >> 1; if(ps <= mid) edt(ls, l, mid, ps, d, dd); else edt(rs, mid+1, r, ps, d, dd); mi[x] = min(mi[ls], mi[rs]); mx[x] = max(mx[ls], mx[rs]); } inline segnode gmin(int x, int l, int r, int L, int R) { if(L > R) return segnode(inf, -1); if(L <= l && r <= R) return mi[x]; int mid = l+r>>1; segnode ret = segnode(inf, -1); if(L <= mid) ret = min(ret, gmin(ls, l, mid, L, R)); if(R > mid) ret = min(ret, gmin(rs, mid+1, r, L, R)); return ret; } inline segnode gmax(int x, int l, int r, int L, int R) { if(L > R) return segnode(-inf, -1); if(L <= l && r <= R) return mx[x]; int mid = l+r>>1; segnode ret = segnode(-inf, -1); if(L <= mid) ret = max(ret, gmax(ls, l, mid, L, R)); if(R > mid) ret = max(ret, gmax(rs, mid+1, r, L, R)); return ret; } }T; int pos[M]; int f[M], s[M]; struct intervals { int l, r; intervals() {} intervals(int l, int r) : l(l), r(r) {} friend bool operator < (intervals a, intervals b) { return a.r < b.r || (a.r == b.r && a.l < b.l); } }a[M]; int main() { // freopen("infection.in", "r", stdin); // freopen("infection.out", "w", stdout); cin >> n; for (int i=1; i<=n; ++i) scanf("%d%d", &p[i].x, &p[i].v); sort(p+1, p+n+1, cmp_pos); for (int i=1; i<=n; ++i) p[i].ps = i; sort(p+1, p+n+1, cmp_va); for (int i=1; i<=n; ++i) T.edt(1, 1, n, p[i].ps, p[i].v, i); // for (int i=1; i<=n; ++i) printf("pos = %d, value = %d, x = %d, id = %d\n", p[i].ps, p[i].v, p[i].x, i); for (int i=1; i<=n; ++i) { a[i].r = T.gmax(1, 1, n, 1, p[i].ps-1).id; if(a[i].r == -1) a[i].r = i; a[i].l = T.gmin(1, 1, n, p[i].ps+1, n).id; if(a[i].l == -1) a[i].l = i; a[i].l = min(a[i].l, i); a[i].r = max(a[i].r, i); // printf("%d %d\n", a[i].l, a[i].r); } sort(a+1, a+n+1); f[0] = s[0] = 1; for (int i=1, j=1; i<=n; ++i) { s[i] = s[i-1]; for (; j<=n && a[j].r == i; ++j) { // printf("%d %d %d\n", i, a[j].r, s[a[j].r]); int tem = s[a[j].r] - ((a[j].l == 1) ? 0 : s[a[j].l-2]); if(tem < 0) tem += mod; f[i] += tem; if(f[i] >= mod) f[i] -= mod; s[i] = s[i-1] + f[i]; if(s[i] >= mod) s[i] -= mod; } } cout << f[n] << endl; return 0; }
View Code

「6月雅禮集訓 2017 Day8」infection