zzz的口胡记
我想到一个好方法:没有时间写的题就写个题解草过去
Loj6100. 「2017 山东二轮集训 Day1」第一题
解题思路
如果对于每个位置,我们能够找到最远的断点,那么可以用主席树轻松解决
对于一个数,请只看它的最高位,如果异或上最高位 1 变 0,后面全 1 也没用
对于每一位分别考虑,二分查找第二个 1 出现在哪一位置,对所有的位取 min 即可
Loj6101. 「2017 山东二轮集训 Day1」第二题
解题思路
笛卡尔树老常见套路了,建出笛卡尔树然后倒着考虑,因为从下到上的一次填充不能够分成两叉,但从上到下的一定可以补到下面来,所以从上到下的贪心即可
const int N = 205000;
ll n, k;
ll H[N], len[N], sum[N], ans;
int f[N], st[N], deg[N], q[N], l, r, tp;
int main() {
read(n), read(k);
for (int i = 1;i <= n; i++) {
read(H[i]); int t = 0;
while (tp && H[st[tp]] >= H[i]) t = st[tp--];
if (t) f[t] = i;
st[++tp] = i, f[i] = st[tp-1];
}
for (int i = 1;i <= n; i++) len[i] = 1, deg[f[i]]++;
l = 0, r = -1;
for (int i = 1;i <= n; i++)
!deg[i] && (q[++r] = i);
while (l <= r) {
int x = q[l++];
sum[x] += len[x] * (H[x] - H[f[x]]);
if (sum[x] > 0) {
ll tp = (sum[x] - 1) / k + 1;
sum[x] -= tp * k, ans += tp;
}
sum[f[x]] += sum[x], len[f[x]] += len[x], deg[f[x]]--;
!deg[f[x]] && (q[++r] = f[x]);
}
write(ans);
return 0;
}