首页 > 其他分享 >P4690 镜中的昆虫 (动态区间颜色数) 题解

P4690 镜中的昆虫 (动态区间颜色数) 题解

时间:2024-10-07 08:59:49浏览次数:8  
标签:pre Oper return int 题解 P4690 ++ 镜中 节点

Statement

  • 区间涂颜色
  • 区间颜色数

Solution

\(O(\text{polysqrt})\)

略。

\(O(\text{polylog})\)

颜色段均摊有两层含义:

  • 随机数据下:任意时刻的颜色段个数期望 \(O(\log n)\)
  • 非随机数据下:每次推平时访问的颜色段个数均摊 \(O(n)\)

首先维护每个点 \(i\) 的 \(pre_i\),一次询问相当于二维偏序。

考虑单点修咋做,他对 \(pre\) 的修改是 \(O(1)\) 的,一次修改看成一次删除 + 一次插入,可以三维偏序完成。

考虑这题咋做。

结论:进行所有区间修改后,\(pre\) 数组的单点修改次数是 \(O(n+m)\) 的。

我们称一个颜色段为一个节点,注意到如果一个节点整体赋上一个值,那么只有节点第一个数、原先最后一个数的后继、现在最后一个数的后继的 \(pre\) 会被修改。

考虑 ODT 的过程,每次修改,我们先将两端的节点分裂,然后删除中间节点,再换成一个同一个节点。

分裂和更换的过程,就是删除若干个节点,再添加至多三个节点。对 \(pre\) 数组的修改次数和删除的节点数同阶。而每个节点至多删除一次,我们添加的节点个数是 \(O(m)\) 的,初始的节点个数是 \(O(n)\) 的。因此,\(pre\) 数组的单点修改次数是 \(O(n+m)\) 的。

既然这样,我们就只需找到 \(pre\) 数组被修改的位置和时间,然后按单点修改的方式做就好了!

怎么找呢?其实就是上面复杂度分析那个过程。我们直接拿个 ODT 维护,然后每次修改就可以找出若干个可能被修改的节点,然后对这些节点求修改后的 \(pre\) 即可。怎么求 \(pre\)?我们对每种颜色开个 ODT 即可。

Code

柯朵莉树写法是跟 251Sec 学的。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = (j); i <= (k); ++i)
#define reo(i, j, k) for (int i = (j); i >= (k); --i)
typedef long long ll;
const int N = 2e5 + 10, M = 2e6 + 10;
int n, m, a[N], pre[N], buc[N];
map<int, int> mp;
int btot;

struct Operations {
	int pos, val, tim, xishu, id;
} Oper[M], tmp[M];
int optot, qtot, ans[N];

struct ODTNode {
	int l, r, v;
	bool operator< (const ODTNode& o) const {
		return l < o.l;
	}
};
struct ODT {
	typedef set<ODTNode>::iterator iter;
	set<ODTNode> tr, col[N];
	iter Insert(int l, int r, int v) {
		col[v].insert({l, r, v});
		return tr.insert({l, r, v}).first;
	}
	void Delete(int l, int r, int v) {
		col[v].erase({l, r, v});
		tr.erase({l, r, v});
	}
	iter Split(int p) {
		iter it = tr.lower_bound({p, 0, 0});
		if (it != tr.end() && it->l == p) return it;
		--it;
		int l = it->l, r = it->r, v = it->v;
		Delete(l, r, v);
		Insert(l, p - 1, v);
		return Insert(p, r, v);
	}
	int Pre(int p) {
		iter it = --tr.upper_bound({p, 0, 0});
		if (it->l != p) return p - 1;
		else {
			int v = it->v;
			it = col[v].lower_bound({p, 0, 0});
			if (it != col[v].begin()) return (--it)->r;
			else return 0;
		}
	}
	int Suf(int p) {
		iter it = --tr.upper_bound({p, 0, 0});
		if (it->r != p) return p + 1;
		else {
			int l = it->l, v = it->v;
			it = col[v].lower_bound({l + 1, 0, 0});
			if (it != col[v].end()) return it->l;
			else return n + 1;
		}
	}
	void Assign(int l, int r, int v, int t) {
		iter itr = Split(r + 1), itl = Split(l);
		vector<int> vec;
		for (iter it = itl; it != itr; ++it) {
			int pl = it->l, pr = it->r, pv = it->v, x = Suf(pr);
			vec.push_back(pl);
			if (x > r && x != n + 1) vec.push_back(x);
			col[pv].erase(*it);
		}
		tr.erase(itl, itr);
		Insert(l, r, v);
		int x = Suf(r);
		if (x != n + 1) vec.push_back(x);
		for (int p : vec) {
			Oper[++optot] = {p, pre[p], t, -1, 0};
			Oper[++optot] = {p, pre[p] = Pre(p), t, 1, 0};
		}
	}
} odt;

struct BIT {
	int sum[N];
	BIT() {
		memset(sum, 0, sizeof(sum));
	}
	void Upd(int x, int v) {
		for (++x; x < N; x += x & -x) sum[x] += v;
	}
	int Qry(int x) {
		int res = 0;
		for (++x; x; x -= x & -x) res += sum[x];
		return res;
	}
} bit;

void CDQ(int l, int r) {
	if (l == r) return;
	int mid = (l + r) >> 1;
	CDQ(l, mid), CDQ(mid + 1, r);
	int pos = l;
	rep(j, mid + 1, r) {
		if (!Oper[j].id) continue;
		while (pos <= mid && Oper[pos].pos <= Oper[j].pos) {
			if (!Oper[pos].id) bit.Upd(Oper[pos].val, Oper[pos].xishu);
			++pos;
		}
		ans[Oper[j].id] += Oper[j].xishu * bit.Qry(Oper[j].val);
	}
	rep(i, l, pos - 1) if (!Oper[i].id) bit.Upd(Oper[i].val, -Oper[i].xishu);
	int tp = l;
	for (int i = l, j = mid + 1; i <= mid || j <= r; )
		if (i <= mid && (j > r || Oper[i].pos <= Oper[j].pos)) tmp[tp++] = Oper[i++];
		else tmp[tp++] = Oper[j++];
	rep(i, l, r) Oper[i] = tmp[i];
}

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr);
	cin >> n >> m;
	rep(i, 1, n) {
		cin >> a[i];
		if (!mp.count(a[i])) mp[a[i]] = ++btot;
		a[i] = mp[a[i]];
		pre[i] = buc[a[i]];
		buc[a[i]] = i;
		Oper[++optot] = {i, pre[i], 0, 1, 0};
		odt.Insert(i, i, a[i]);
	}
	rep(i, 1, m) {
		int op, l, r, x;
		cin >> op >> l >> r;
		if (op == 1) {
			cin >> x;
			if (!mp.count(x)) mp[x] = ++btot;
			x = mp[x];
			odt.Assign(l, r, x, i);
		} else {
			Oper[++optot] = {r, l - 1, i, 1, ++qtot};
			Oper[++optot] = {l - 1, l - 1, i, -1, qtot};
		}
	}
	CDQ(1, optot);
	rep(i, 1, qtot) cout << ans[i] << '\n';
	return 0;
}

标签:pre,Oper,return,int,题解,P4690,++,镜中,节点
From: https://www.cnblogs.com/laijinyi/p/18449756

相关文章

  • Codeforces Rund 977 div2 个人题解(A~E1)
    CodeforcesRund977div2个人题解(A,B,C1,C2,E1)Dashboard-CodeforcesRound977(Div.2,basedonCOMPFEST16-FinalRound)-Codeforces火车头#define_CRT_SECURE_NO_WARNINGS1#include<algorithm>#include<array>#include<bitset>#includ......
  • 【题解】C - STEP
    目录题目内容DescriptionInputOutput数据规模与约定做法一思路代码做法2思路代码题目内容原题:洛谷P6492Description给定一个长度为\(n\)的字符序列\(a\),初始时序列中全部都是字符L。有\(q\)次修改,每次给定一个\(x\),若\(a_x\)为L,则将\(a_x\)修改成R,否则将\(a_x\)......
  • 常见问题解决 --- maven手动安装依赖jar包报错
    报错内容:执行命令mvninstall:install-file-DgroupId=com.beidouapp-DartifactId=SSDK-Dversion=4.0.2.0 -Dfile=C:\1\SSDK-Release-4.0.2.0.jar-Dpackaging=jar报错Unknownlifecyclephase“.ggstar“.Youmustspecifyavalidlifecyclephaseoragoal原因:在pow......
  • CCF-CSP认证资格考试题解系列——第4次第2题数字排序
    #include<iostream>#include<algorithm>usingnamespacestd;structre{ intvalue;//数值 intnum;//次数}re[1010];boolcmp(structrea,structreb){ if(a.num==b.num)returna.value<b.value;//次数相同是小的优先 returna.num>b.num;//次数不相同是次数优......
  • CCF-CSP认证资格考试题解系列——第4次第3题节日
    #include<iostream>usingnamespacestd;intm[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};intis_run(intyear){ if(year%400==0||(year%4==0&&year%100))return1; return0;}intgetdays(intyear,intmonth){ if(month==2)returnm[month]+i......
  • ABC374 E 题解
    ABC374E题解E-SensorOptimizationDilemma2题目链接:AT|洛谷容易发现答案可以二分。于是我们把问题转化为了判定性问题:给定目标\(x\),能否在花费不超过预算的情况下,使得每个过程的产量都不低于\(x\)?进一步,由于各个过程的生产互不相关,所以我们要尽可能让每个过程的费......
  • P7078 [CSP-S2020] 贪吃蛇 题解
    P7078[CSP-S2020]贪吃蛇这题好啊题目传送门看到题之后觉得有点像砍蚯蚓的那道题看看题目可以证明,若一条蛇在吃完之后不是最弱的那一条蛇,那么他一定会选择吃,证明如下设蛇长为\(a_{1,\dots,n}\)且依次递增,那么很明显的因为​......
  • 鲁的智力 题解
    题意有\(n\)个人,\(m\)个学科,你第\(i\)门学科排在第\(a_i\)名,且每个人在每个学科得到的分数是一个\(0\)到\(1\)之间的一个实数,求你总分排名的最大、小值。题解先考虑排名最高的情况。我们可以每一科都这样构造:\[b_1=1\]\[b_2=1-\Deltax\]\[b_3=1-2\De......
  • 游览计划 题解
    题意给定一张无向图,选取四个点\(a\neb\nec\ned\),求\(f(a,b)+f(b,c)+f(c,d)\)的最大值,其中\(f(u,v)\)表示点\(u\)到点\(v\)的最短路长度。题解如果顺着枚举四个点\(a\)、\(b\)、\(c\)、\(d\),是一个\(n^4\)的复杂度,显然过不了。但是我们发现如果确定......
  • 洛谷 P3523 题解
    洛谷P3523[POI2011]DYN-Dynamite分析二分答案,问题转化为:对于给定的\(K\),选择尽可能少的节点,使得所有关键节点都被「覆盖」。对于一个关键节点,「覆盖」的定义为:存在一个被选择的点与这个关键节点的距离不大于\(K\)。方便起见,我们指定\(1\)号节点是这棵树的根节点。我们......