第十分块
好不容易卡过去了,纪念一下。 link
可离线,很容易想到莫队。带修不好维护,考虑 \([l,r]\) 用 ds 维护,莫队扫时间和值域这两维就好了。
所以我们需要支持维护一个 \(\mathtt {01}\) 序列,动态修改某个位置上的数,并求出所有极长 \(\mathtt 1\) 的段的长度平方和。
注意一般情况时间是必须带 \(\log\) 的,可以尝试只支持 \(\mathtt 0\) 变成 \(\mathtt 1\) 或者撤销最近一次操作,这契合回滚莫队的机制。
按时间分块,同一块内,所有询问值域从小到大扫描,每次询问前需要额外加入 \(\mathcal O(\sqrt n)\) 次单点修改。
可以求出当前时间块的修改的所有位置上的历史最大值,先按照历史最大值的顺序加入。在每个询问前,再求出这些位置上的真实值,这样的确只有 \(\mathtt 0\) 变为 \(\mathtt 1\) 的修改。
维护 \(\mathtt {01}\) 序列中每个极长 \(\mathtt 1\) 段的左端点和右端点位置的匹配,即可快速找到一个左端点对应的右端点 / 一个右端点对应的左端点。
撤销是容易的,时间复杂度 \(\mathcal O((n + m) \sqrt n)\)。
点击查看代码
#include <bits/stdc++.h>
namespace Initial {
#define ll int
#define ull unsigned long long
#define fi first
#define se second
#define mkp make_pair
#define pir pair <int, int>
#define pb push_back
#define i128 __int128
using namespace std;
const ll maxn = 3e5 + 10, inf = 2e9, mod = 1e9 + 7;
ll power(ll a, ll b = mod - 2) {
ll s = 1;
while(b) {
if(b & 1) s = s * a %mod;
a = a * a %mod, b >>= 1;
} return s;
}
template <class T>
const inline ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
template <class T>
const inline void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
template <class T>
const inline void chkmax(T &x, const T y) { x = x < y? y : x; }
template <class T>
const inline void chkmin(T &x, const T y) { x = x > y? y : x; }
} using namespace Initial;
namespace Read {
char buf[1 << 22], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
template <class T>
const inline void rd(T &x) {
char ch; bool neg = 0;
while(!isdigit(ch = getchar()))
if(ch == '-') neg = 1;
x = ch - '0';
while(isdigit(ch = getchar()))
x = (x << 1) + (x << 3) + ch - '0';
if(neg) x = -x;
}
} using Read::rd;
ll n, m, a[maxn]; long long ans[maxn];
struct Mdf { ll x, y; }; vector <Mdf> mdf;
struct Qry { ll ti, l, r, x, id; }; vector <Qry> qry;
ll max_val[maxn], now, h[maxn], ht;
ll nxt[maxn], pos[maxn], hd[maxn], tot;
void ins(ll x, ll y) {
pos[++tot] = y, nxt[tot] = hd[x];
hd[x] = tot;
}
namespace DS {
ll st[maxn], stk[maxn], top, B, bl[maxn];
ll res[maxn]; short cnt[maxn]; bool cov[maxn];
void add(const ll x) {
const ll u = bl[x]; ll l = 0, r = 0;
++cnt[u], cov[x] = true, stk[++top] = x;
if(bl[x - 1] == u) l = st[x - 1];
if(bl[x + 1] == u) r = st[x + 1];
if(!l) l = x; if(!r) r = x;
st[l] = r, st[r] = l;
const ll A = x - l, B = r - x, C = A + B + 1;
res[u] += C * C - A * A - B * B;
}
void restore() {
const ll x = stk[top--], u = bl[x]; ll l = 0, r = 0;
--cnt[u], cov[x] = false;
if(bl[x - 1] == u && cov[x - 1])
st[l = st[x - 1] < x? st[x - 1] : x - 1] = x - 1;
else l = x;
if(bl[x + 1] == u && cov[x + 1])
st[r = st[x + 1] > x? st[x + 1] : x + 1] = x + 1;
else r = x;
st[x] = 0;
const ll A = x - l, B = r - x, C = A + B + 1;
res[u] -= C * C - A * A - B * B;
}
} using namespace DS; ll bin[maxn];
ll l, r;
long long ret; ll sum, cc;
void work(const ll u) {
ll ul = (u - 1) * B + 1, ur = u * B;
if(l <= ul && ur <= r) {
cc += cnt[u];
if(cnt[u] == ur - ul + 1) sum += ur - ul + 1;
else {
if(st[ul]) {
sum += st[ul] - ul + 1;
ret -= (st[ul] - ul + 1) * (st[ul] - ul + 1);
}
ret += 1ll * sum * sum + res[u], sum = 0;
if(st[ur]) {
sum = ur - st[ur] + 1;
ret -= sum * sum;
}
}
} else {
chkmax(ul, l), chkmin(ur, r);
for(ll i = ul; i <= ur; i++)
if(cov[i]) ++sum, ++cc;
else ret += 1ll * sum * sum, sum = 0;
}
}
const long long getans() {
ret = sum = cc = 0;
for(register ll u = bl[l]; u <= bl[r]; u++) work(u);
return ret + 1ll * sum * sum + cc;
}
bool cmp(const Qry a, const Qry b) { return a.x < b.x; }
void solve(const ll L, const ll R) {
memset(hd, 0, sizeof hd), tot = 0;
for(register ll i = 1; i <= n; i++) max_val[i] = a[i];
ht = 0;
for(register ll i = L; i < R; i++)
h[++ht] = mdf[i].x, chkmax(max_val[mdf[i].x], mdf[i].y);
for(register ll i = 1; i <= n; i++) ins(max_val[i], i);
stable_sort(h + 1, h + 1 + ht);
ht = unique(h + 1, h + 1 + ht) - h - 1;
ll to = now;
while(to < qry.size() && qry[to].ti <= R) ++to;
stable_sort(qry.begin() + now, qry.begin() + to, cmp);
for(register ll i = now, j = 1; i < to; i++) {
Qry Q = qry[i];
while(j <= Q.x)
for(ll k = hd[j++]; k; k = nxt[k])
add(pos[k]);
const ll tt = top;
for(register ll k = Q.ti - 1; k >= L; k--)
if(bin[mdf[k].x] <= i) {
bin[mdf[k].x] = i + 1;
if(max_val[mdf[k].x] > Q.x && mdf[k].y <= Q.x)
add(mdf[k].x);
}
for(register ll k = 1; k <= ht; k++)
if(bin[h[k]] <= i && max_val[h[k]] > Q.x
&& a[h[k]] <= Q.x) add(h[k]);
l = Q.l, r = Q.r, ans[Q.id] = getans();
while(top > tt) restore();
} now = to, top = 0;
memset(st, 0, sizeof st);
memset(cov, 0, sizeof cov);
for(ll i = 1; i <= bl[n]; i++) cnt[i] = res[i] = 0;
}
signed main() {
rd(n), rd(m); B = max(1, (ll) pow(n * 3 / 4, 0.5));
for(register ll i = 1; i <= n; i++) rd(a[i]), bl[i] = (i - 1) / B + 1;
for(register ll i = 1; i <= m; i++) {
ll op; rd(op);
if(op == 1) {
Mdf tmp; rd(tmp.x), rd(tmp.y);
mdf.pb(tmp); ans[i] = -1;
} else {
Qry tmp; rd(tmp.l), rd(tmp.r), rd(tmp.x);
tmp.id = i, tmp.ti = mdf.size(), qry.pb(tmp);
}
}
ll mdf_B = max(1, (ll) pow(mdf.size(), 0.58)), ul = 0, ur;
while(1) {
ur = min(ul + mdf_B, (ll) mdf.size() + 1);
solve(ul, ur - 1);
if(ur > mdf.size()) break;
for(ll i = ul; i < ur; i++) a[mdf[i].x] = mdf[i].y;
ul = ur;
}
for(register ll i = 1; i <= m; i++)
if(ans[i] >= 0) printf("%lld\n", ans[i] >> 1);
return 0;
}

浙公网安备 33010602011771号