【题解】P7416 [USACO21FEB] No Time to Dry P
这一类问题考虑离线下来,扫描线右端点然后用一个 ds 来维护左端点。假设当前右端点的位置从 \(r-1\) 变成哪里 \(r\),则考虑 \(a_r\) 上一次出现的位置 \(pos\)。容易观察到结论:若有 \(a_i\le \min\limits_{j=pos}^i a_j\) 则这中间所有其他的颜色都可以直接覆盖掉当前颜色,可以一次涂过去。否则这个地方涂到 \(pre\) 位置之后还需要额外再涂色一次。因此想到拿一个线段树或者 BIT 来维护答案,其中:
- 若当前的情况是 \(a_i\le\min\limits_{j=pos}^ia_j\),则只需要更新 \(\forall j\in[pos+1,i],a_j\leftarrow a_j+1\)。
- 否则,当前右端点到之前的每一个地方都需要额外单独染色一次,更新 \(\forall j\in[1,i],a_j\leftarrow a_j+1\)。
区间静态最值用 ST 表简单维护,总时间复杂度为 \(O((n+Q)\log n)\) 可以通过该题。
namespace Loyalty
{
int tree[N];
vector<pair<int, int>> Q[N];
int a[N], lg[N], f[N][20], la[N], pre[N], res[N];
inline void add(int x, int v) { for (; x < N; x += (x &- x)) tree[x] += v; }
inline int qry(int x) { int s = 0; for (; x; x -= (x &- x)) s += tree[x]; return s; }
inline int qmin(int l, int r) { int k = lg[r - l + 1]; return min(f[l][k], f[r - (1 << k) + 1][k]); }
inline void init() {}
inline void main([[maybe_unused]] int _ca, [[maybe_unused]] int _atc)
{
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; ++i)
{
int x;
cin >> x;
add(i, x), add(i + 1, -x);
}
while (q--)
{
int o;
cin >> o;
if (o == 1)
{
int l, r, k;
cin >> l >> r >> k;
add(l, k), add(r + 1, -k);
}
else
{
int x;
cin >> x;
cout << qry(x) << '\n';
}
}
}
}

浙公网安备 33010602011771号