Ynoi 镜中的昆虫
还没写完,先放一下。
思路还是很自然的啊!
先考虑静态,对第 \(i\) 个位置记录 \(pre_i\) 表示上一个和他相同的值的位置,那么对于区间的询问就是查询 \([l, r]\) 中有多少个位置 \(i\) 的 \(pre_i < l\),可持久化线段树就可以做到。
考虑带上修改,如果是单点修改,那我直接树套树也行!
考虑带上区间修改,那么就考虑珂朵莉树,对于修改操作 \([l, r, x]\),我们会将 \([l, r]\) 这段区间的颜色暴力推平成 \(x\),那他们的 \(pre_i\) 的变化是怎么变的?
对于位置 \(l\),\(pre_l\) 变成上一个颜色为 \(x\) 的右端点。
对于位置 \(i \in (l, r]\),\(pre_i\) 都变成 \(i-1\)。
将下一个颜色为 \(x\) 的区间的左端点 \(l'\) 的 \(pre_{l'}\) 改成 \(r\)。
那么我们在珂朵莉树上,可以首先暴力修改第一种和第三种情况,这样端点变化只有两个,而对于第二种情况,我们直接暴力删除这一段区间,然后直接加入新的区间 \((l, r]\) 即可。
同时我们用 \(\textbf{vector}\) 来存下当前的颜色为 \(x\) 的区间有哪些,这样对于情况一,三,我们可以在 \(\log (n)\) 的时间内进行处理,那么整体修改一个区间的复杂度就为 \(\log(n)\) 的。
然后每次对于操作一和操作二,我们可以看成是一个单点修改。
然后如何进行 cdq,我们考虑静态是直接 \((i, pre_i)\) 然后进行二维数点,如果我现在要改一个点呢,你加一维时间,表示修改时间。
然后添加两个四元组表示 \((t, i, pre_i, -1)\) 表示在 \(t\) 时刻,\(i\) 位置的 \(pre_i\) 被删除,贡献 \(-1\)。
以及 \((t, i, *pre_i, 1)\) 表示在 \(t\) 时刻,\(i\) 位置的 \(*pre_i\) 被添加,贡献 \(1\)。
这就是单点修改了,然后根据颜色段均摊的结论,你发现了一些好玩的事情啊!
就是 \(pre_i\) 的变化只会变化 \((n + m)\) 次,那你等价于做 \((n + m)\) 次的单点修改,这不就完了?
就这,好吧我还以为多高妙,一开始居然细节没想清楚。
我先出去放纵一下自己,等我有空再来写。
re 了,有空再来调。
/*
* @Author: Pitiless0514
* @Date: 2022-06-17 10:17:25
* @LastEditors: Pt
* @LastEditTime: 2022-06-23 10:59:46
* @Description: どんなに一生懸命やっても、得られないものがある。 最初から知らないだけで、痛みは起こりませんよ。
*/
// 德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱
// 德丽莎的可爱在于德丽莎很可爱,德丽莎为什么很可爱呢,这是因为德丽莎很可爱!
#include <bits/stdc++.h>
using namespace std;
namespace io {
const int SIZE = (1 << 9) + 1; char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush () { fwrite (obuf, 1, oS - obuf, stdout); oS = obuf; }
inline void putc (char x) { *oS ++ = x; if (oS == oT) flush (); }
template <class I> inline void gi (I &x) { for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1; for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f; }
string getstr(void) { string s = ""; char c = gc(); while (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == EOF) c = gc(); while (!(c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == EOF))s.push_back(c), c = gc(); return s;}
template <class I> inline void print (I x) { if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x; while (x) qu[++ qr] = x % 10 + '0', x /= 10; while (qr) putc (qu[qr --]); }
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: gi; using io :: putc; using io :: print;
#define V inline void
#define I inline int
template<class T> bool chkmin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool chkmax(T &a, T b) { return a < b ? (a = b, true) : false; }
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define repd(i, l, r) for (int i = (l); i >= (r); i--)
const int N = 1e5 + 777;
int n, m, a[N], b[N], tot; //离散化和读入
int las[N]; //记录上一次 a[i] 出现位置在
int pre[N]; //记录第i个位置上一个和他相同的位置是
struct node {
int l, r, v;
node () : l(), r(), v() {}
node (int x,int y,int z) : l(x), r(y), v(z) {}
friend bool operator < (node x, node y) { return x.l < y.l; }
};
set <node> s;
struct cdq2 {
int t, i, pi, val, type;
cdq2(int tt = 0,int ii = 0,int pp = 0,int vv = 0,int tp = 0) {
t = tt, i = ii, pi = pp, val = vv, type = tp;
}
};
vector <cdq2> pt;
set < pair<int,int> > st[N];
int nowtim;
/* 16777216 */
auto split(int p) {
auto it = s.upper_bound(node(p, 0, 0));
--it;
if (it -> l == p) return it;
node now = *it;
s.erase(now); s.emplace(now.l, p - 1, now.v);
return s.emplace(p, now.r, now.v).first;
}
void assign(int l,int r,int col) {
auto itr = split(r + 1), itl = split(l);
s.erase(itl, itr);
s.emplace(l, r, col);
}
void calc(int l,int r,int col) { //将 [l, r] 全部变成 col
auto itr = split(r + 1), itl = split(l);
auto it = itl;
for (; itl != itr; ++itl) {
auto itqq = st[ (*itl).v ].find( {(*itl).l, (*itl).r} );
st[(*itl).v].erase(itqq);
// cout << "qwq : " << (*itl).v << " " << (*itl).l << " " << (*itl).r << " " << pre[(*itl).l] << "\n";
if (it == itl) {
continue;
} else {
pt.push_back( cdq2(nowtim, (*itl).l, pre[(*itl).l], -1, 0) );
pre[ (*itl).l ] = (*itl).l - 1;
pt.push_back( cdq2(nowtim, (*itl).l, pre[(*itl).l], +1, 0) );
}
}
s.erase(it, itr);
s.emplace(l, r, col);
st[col].insert( {l, r} );
auto qwq = st[col].find( {l, r} );
if (qwq != st[col].begin()) {
qwq--;
int R = (*qwq).second;
pt.push_back( cdq2(nowtim, (*it).l, pre[(*it).l], -1, 0) );
pre[(*it).l] = R;
pt.push_back( cdq2(nowtim, (*it).l, pre[(*it).l], +1, 0) );
} else {
pt.push_back( cdq2(nowtim, (*it).l, pre[(*it).l], -1, 0) );
pre[ (*it).l ] = 0;
pt.push_back( cdq2(nowtim, (*it).l, pre[(*it).l], +1, 0) );
}
qwq = st[col].find( {l, r} ); qwq ++;
// cout << "QAQ\n";
// for (auto itt : st[col]) {
// cout << (itt).first << " " << (itt).second << "\n";
// }
if (qwq != st[col].end()) {
int L = (*qwq).first;
pt.push_back( cdq2(nowtim, L, pre[L], -1, 0));
pre[L] = r;
pt.push_back( cdq2(nowtim, L, pre[L], +1, 0));
}
}
int ans[N];
class Fenwikc_Tree {
public :
int c[N];
int lowbit(int x) { return x & (-x); }
void change(int x,int val) {
for (int i = x; i <= n; i += lowbit(i)) c[i] += val;
}
int ask(int x) {
int ans = 0;
for (int i = x; i; i -= lowbit(i)) ans += c[i]; return ans;
}
int range(int l,int r) { return ask(r) - ask(l - 1); }
void remake(int x) {
for (int i = x; i <= n; i += lowbit(i)) {
if (!c[i]) break;
else c[i] = 0;
}
}
} t1;
int id[120005];
vector <int> tmp;
void CDQ(int l,int r) {
if (l == r) return;
int mid = (l + r) >> 1;
CDQ(l, mid), CDQ(mid + 1, r);
// vector <int> tmp;
tmp.clear();
int i = l, j = mid + 1;
while (i <= mid && j <= r) {
if (pt[ id[i] ].i <= pt[ id[j] ].i) {
if (pt[ id[i] ].type == 0) t1.change(pt[ id[i] ].pi, pt[ id[i] ].val);
tmp.push_back( id[i] ); i++;
} else {
if (pt[ id[j] ].type == 1) {
ans[ pt[ id[j] ].t ] += pt[ id[j] ].val * t1.ask(pt[ id[j] ].pi);
}
tmp.push_back( id[j] ); j++;
}
}
while (j <= r) {
if (pt[ id[j] ].type == 1) {
ans[ pt[ id[j] ].t ] += pt[ id[j] ].val * t1.ask(pt[ id[j] ].pi);
}
tmp.push_back(id[j]); j++;
}
rep (k, l, i - 1)
if (pt[ id[k] ].type == 0) t1.remake(pt[ id[k] ].pi);
while (i <= mid) { tmp.push_back(id[i]); i++; }
for (i = l; i <= r; i++) id[i] = tmp[i - l];
}
// #define LOCAL_DEFINE
signed main () {
#ifdef LOCAL_DEFINE
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif
gi(n), gi(m);
rep (i, 1, n) gi(a[i]), b[i] = a[i]; tot = n;
sort(b + 1, b + tot + 1); tot = unique(b + 1, b + tot + 1) - (b + 1);
// rep (i, 1, tot) cout << b[i] << " "; cout << "qwq\n";
rep (i, 1, n) a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
rep (i, 1, n) {
int j = i;
while (a[j + 1] == a[i] && j < n) j++;
// (i, j) 这段的值一样
rep (k, i + 1, j) pre[k] = k - 1;
pre[i] = las[ a[i] ]; las[ a[i] ] = j;
s.emplace(i, j, a[i]); st[ a[i] ].insert( {i, j} );
// cout << i << " " << j << " " << a[i] << "wpshi bindir\n";
i = j;
}
// rep (i, 1, n) cout << i << " " << pre[i] << "\n";
pt.push_back(cdq2(-1, 0, 0, 0, 0));
rep (i, 1, n) pt.push_back(cdq2(0, i, pre[i], 1, 0));
// for (auto it : pt) {
// cout << it.t << " " << it.i << " " << it.pi << " " << it.val << " " << it.type << "\n";
// }
// rep (i, 1, n) pt.push_back( cdq2(0, i, pre[i], 1, 0) );
rep (i, 1, m) {
int op, l, r; gi(op), gi(l), gi(r);
nowtim = i;
if (op == 1) {
int x; gi(x);
calc(l, r, x);
}
if (op == 2) {
pt.push_back( cdq2(i, r, l - 1, 1, 1) );
pt.push_back( cdq2(nowtim, l - 1, l - 1, -1, 1));
// cout << " qwq : " << l - 1 << "\n";
}
}
int pcnt = pt.size() - 1;
rep (i, 1, pcnt) pt[i].pi++;
rep (i, 1, pcnt) {
auto it = pt[i];
// cout << it.t << " " << it.i << " " << it.pi << " " << it.val << " " << it.type << "\n";
}
vector <int> ri;
int mxx = 0, mxy = 0, mxz = 0;
rep (i, 1, pcnt) {
if (pt[i].type) chkmax(mxx, pt[i].t), chkmax(mxy, pt[i].i), chkmax(mxz, pt[i].pi);
}
rep (i, 1, pcnt) {
if (pt[i].type || (pt[i].t <= mxx && pt[i].i <= mxy && pt[i].pi <= mxz)) ri.push_back(i);
}
pcnt = ri.size();
rep (i, 1, pcnt) id[i] = ri[i - 1];
// rep (i, 1, pcnt) cout << id[i] << " "; cout << "\n";
// cout << pcnt << "\n";
CDQ(1, pcnt);
// rep (i, 1, pcnt) {
// cout << pt[ id[i] ].t << " " << pt[ id[i] ].i << " " << pt[ id[i] ].pi << " " << pt[ id[i] ].val <<" " << pt[ id[i] ].type <<" \n";
// }
rep (i, 1, m) {
if (ans[i]) printf("%d\n", ans[i]);
}
// for (register int i = 1;i <= m;i++) {
// if (ans[i]) printf("%d\n", ans[i]);
// }
// cout << mxx << " " << mxy << " " << mxz << "\n";
// for (auto it : pt) {
// if (it.t <= mxx)
// cout << it.t << " " << it.i << " " << it.pi << " " << it.val << " " << it.type << "\n";
// }
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}