CF56E Domino Principle
题意:
给你一些多米诺骨牌,每个骨牌都有一个高度
h
h
h,它倒下时会放到
[
x
+
1
,
x
+
h
−
1
]
[x+1,x+h-1]
[x+1,x+h−1],在
x
x
x轴上从左到右排列在一起,问,每一个倒向右边的时候会压倒多少个骨牌?给定的骨牌并不是按照
x
x
x从小到大的顺序排列的。
思路:线段树优化DP
先对骨牌按
x
x
x排序,然后从右往左推,
d
p
i
dp_i
dpi表示放倒
i
i
i一共放倒的骨牌数,
d
p
i
=
m
a
x
(
d
p
j
+
j
−
i
)
,
(
x
i
+
1
≤
j
≤
x
i
+
h
i
−
1
)
dp_i=max(dp_j+j-i),(x_i+1\le j\le x_i+h_i-1)
dpi=max(dpj+j−i),(xi+1≤j≤xi+hi−1),时间复杂度
O
(
n
2
)
O(n^2)
O(n2),我们用线段树优化
d
p
dp
dp,每次二分出第
i
i
i块牌能压倒的最后一块牌的编号
r
r
r,每次查询
d
p
j
+
j
(
1
≤
j
≤
r
)
dp_j+j(1\le j\le r)
dpj+j(1≤j≤r)的最大值,再减去
i
i
i,最后修改为
d
p
i
+
i
dp_i+i
dpi+i,时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define per(i, a, b) for(int i = (a); i >= (b); --i)
#define debug(x) cout << #x << " = " << x << endl;
#define ll long long
#define endl '\n'
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(), (x).end()
const int N = 1e5 + 10, M = 2 * N;
const ll mod = 1e9 + 7;
const ll inf = 0x3f3f3f3f;
int n;
struct dom {
int x, h, id;
bool operator<(const dom &t) const { return x < t.x; }
} a[N];
int dp[N];
#define ls u << 1
#define rs u << 1 | 1
struct node {
int l, r;
int v;
} tr[N * 4];
void pushup(int u) { tr[u].v = max(tr[ls].v, tr[rs].v); }
void build(int u, int l, int r) {
if(l == r)
tr[u] = {l, r};
else {
tr[u] = {l, r};
int mid = l + r >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
pushup(u);
}
}
void modify(int u, int x, int v) {
if(tr[u].l == x && tr[u].r == x) {
tr[u].v = v;
} else {
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(ls, x, v);
if(x > mid) modify(rs, x, v);
pushup(u);
}
}
int query(int u, int l, int r) {
if(tr[u].l >= l && tr[u].r <= r) {
return tr[u].v;
} else {
int mid = tr[u].l + tr[u].r >> 1;
int res = -inf;
if(l <= mid) res = max(res, query(ls, l, r));
if(r > mid) res = max(res, query(rs, l, r));
return res;
}
}
int ans[N];
void solve() {
cin >> n;
rep(i, 1, n) {
cin >> a[i].x >> a[i].h;
a[i].id = i;
}
sort(a + 1, a + 1 + n);
build(1, 1, n);
// rep(i,1,n) cout<<a[i].x<<' '<<a[i].h<<' '<<a[i].id<<endl;
dp[n] = 1;
ans[a[n].id] = 1;
modify(1, n, n + 1);
per(i, n - 1, 1) {
int l = i, r = n;
while(l < r) {
int mid = l + r + 1 >> 1;
if(a[i].x + a[i].h > a[mid].x)
l = mid;
else
r = mid - 1;
}
if(i == r)
dp[i] = 1;
else
dp[i] = query(1, i, r) - i;
modify(1, i, dp[i] + i);
ans[a[i].id] = dp[i];
}
rep(i, 1, n) cout << ans[i] << ' ';
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
// int _;cin>>_;while(_--)
solve();
return 0;
}