CF803G Periodic RMQ Problem 题解

分析

容易发现,此题可以类似 \(\texttt{ODT}\),将序列分作数块。但为了方便查询一段块的最小值,只能手写平衡树。
平衡树每个结点对应一段,分两种:

  1. \(b[l,r]\)
    此时直接记录 \(l,r\) 以及 \(b[l,r]\) 的最小值即可。
  2. \(c\)\(v\)
    记录 \(c,v\)
    进行操作时,应将左右端点所在块视情况分裂,细节略。

代码

#include<bits/stdc++.h>
namespace IO {
	constexpr int bufsize = 230005;
	char buf[bufsize], *f1, *f2;
	char gtchar() {return f1 == f2 && (f2 = buf + fread(f1 = buf, 1, bufsize, stdin)) == buf? EOF: *f1++;}
	template<typename T> void read(T &ret)
	{
		int f = ret = 0;
		char ch = gtchar();
		while(!isdigit(ch)) f = ch == '-', ch = gtchar();
		while(isdigit(ch)) ret = (ret << 3) + (ret << 1) + (ch ^ 48), ch = gtchar();
		if(f) ret = -ret;
	}
	template<typename T, typename ...t> void read(T &a, t &...b) {read(a), read(b...);}
}using IO::read;
typedef long long ll;
typedef unsigned long long ull;
constexpr int maxn = 100005, inf = 1e9;
std::mt19937 rnd(std::random_device{}() ^ (ull) new char);
int n, k, q, b[maxn];
struct SparseTable {
	int c[17][maxn];
	void init()
	{
		memcpy(c[0], b, sizeof b);
		for(int i = 1; i < 17; i++) for(int j = 1; j <= n; j++)
			c[i][j] = std::min(c[i - 1][j], c[i - 1][j + (1 << i - 1)]);
	}
	int query(int l, int r)
	{
		int len = std::__lg(r - l + 1);
		return std::min(c[len][l], c[len][r - (1 << len) + 1]);
	}
}ST;
struct Treap {
	struct node {
		int mode, l, r, v, mn, ls, rs, sz, p, c;
	}s[maxn << 3];
	int rt, cnt;
	void newnode(int &k)
	{
		k = ++cnt;
		s[k].mn = inf;
		s[k].p = rnd();
	}
	void pushup(int k)
	{
		s[k].mn = std::min({s[s[k].ls].mn, s[s[k].rs].mn, s[k].v});
		s[k].sz = s[s[k].ls].sz + s[s[k].rs].sz + s[k].c;
	}
	int merge(int l, int r)
	{
		if(!l || !r) return l | r;
		int ret;
		if(s[l].p < s[r].p) s[ret = l].rs = merge(s[l].rs, r);
		else s[ret = r].ls = merge(l, s[r].ls);
		pushup(ret);
		return ret;
	}
	void erase(int &root, int k)
	{
		if(root == k) return void(root = merge(s[k].ls, s[k].rs));
		erase(s[root].ls, k);
		pushup(root);
	}
	void init()
	{
		s[0].mn = inf;
		for(int i = 1; i <= k; i++)
		{
			int tmp;
			newnode(tmp);
			s[tmp].l = 1, s[tmp].r = n;
			s[tmp].mn = s[tmp].v = ST.query(1, n);
			s[tmp].sz = s[tmp].c = n;
			rt = merge(rt, tmp);
		}
	}
	void split_size(int k, int rank, int &l, int &r)
	{
		if(!k) return void(l = r = 0);
		int tmp = s[s[k].ls].sz + s[k].c;
		if(tmp <= rank) l = k, split_size(s[k].rs, rank - tmp, s[k].rs, r);
		else r = k, split_size(s[k].ls, rank, l, s[k].ls);
		pushup(k);
	}
	int first(int k)
	{
		while(s[k].ls) k = s[k].ls;
		return k;
	}

	void split(int ql, int qr, int &left, int &mid, int &right)
	{
		split_size(rt, qr, left, right), split_size(left, ql - 1, left, mid);
		int a = first(mid), b = first(right);
		if(!a)// -[--|-|--]-
		{
			erase(right, b);
			s[b].ls = s[b].rs = 0;
			int tmp;
			if(s[b].mode == 0)
			{
				int l = s[b].l, r = s[b].r;
				if(s[left].sz + 1 < ql)
				{
					newnode(tmp);
					s[tmp].l = l, s[tmp].r = ql - 1 - s[left].sz + l - 1;
					s[tmp].mn = s[tmp].v = ST.query(l, s[tmp].r);
					s[tmp].sz = s[tmp].c = s[tmp].r - l + 1;
					left = merge(left, tmp);
					l = s[tmp].r + 1;
				}
				s[b].l = l, s[b].r = qr - s[left].sz + l - 1;
				s[b].mn = s[b].v = ST.query(l, s[b].r);
				s[b].sz = s[b].c = s[b].r - l + 1;
				mid = b;
				l = s[b].r + 1;
				newnode(tmp);
				s[tmp].l = l, s[tmp].r = r;
				s[tmp].mn = s[tmp].v = ST.query(l, r);
				s[tmp].sz = s[tmp].c = r - l + 1;
				right = merge(tmp, right);
			}
			else
			{
				int c = s[b].c, v = s[b].v;
				if(s[left].sz + 1 < ql)
				{
					newnode(tmp);
					s[tmp].mode = 1;
					s[tmp].mn = s[tmp].v = v;
					s[tmp].sz = s[tmp].c = ql - s[left].sz - 1;
					c -= s[tmp].c;
					left = merge(left, tmp);
				}
				s[b].mn = v;
				s[b].sz = s[b].c = qr - ql + 1;
				mid = b;
				c -= qr - ql + 1;
				newnode(tmp);
				s[tmp].mode = 1;
				s[tmp].mn = s[tmp].v = v;
				s[tmp].sz = s[tmp].c = c;
				right = merge(tmp, right);
			}
			return;
		}
		if(ql == s[left].sz + 1) goto la;
		erase(mid, a);
		s[a].ls = s[a].rs = 0;
		int tmp;
		if(s[a].mode == 0)
		{
			int l = s[a].l, r = s[a].r;
			s[a].r = ql - s[left].sz - 1 + l - 1;
			s[a].mn = s[a].v = ST.query(l, s[a].r);
			s[a].sz = s[a].c = s[a].r - l + 1;
			newnode(tmp);
			s[tmp].l = s[a].r + 1, s[tmp].r = r;
			s[tmp].mn = s[tmp].v = ST.query(s[tmp].l, r);
			s[tmp].sz = s[tmp].c = r - s[tmp].l + 1;
		}
		else
		{
			int c = s[a].c, v = s[a].v;
			s[a].mn = v;
			s[a].c = s[a].sz = ql - s[left].sz - 1;
			newnode(tmp);
			s[tmp].mode = 1;
			s[tmp].v = s[tmp].mn = v;
			s[tmp].sz = s[tmp].c = c - s[a].c;
		}
		left = merge(left, a);
		mid = merge(tmp, mid);
		la:
		if(!b || qr == s[left].sz + s[mid].sz) goto lb;
		erase(right, b);
		s[b].ls = s[b].rs = 0;
		if(s[b].mode == 0)
		{
			int l = s[b].l, r = s[b].r;
			s[b].r = qr - s[left].sz - s[mid].sz + l - 1;
			s[b].mn = s[b].v = ST.query(l, s[b].r);
			s[b].sz = s[b].c = s[b].r - l + 1;
			newnode(tmp);
			s[tmp].l = s[b].r + 1, s[tmp].r = r;
			s[tmp].mn = s[tmp].v = ST.query(s[tmp].l, r);
			s[tmp].sz = s[tmp].c = r - s[tmp].l + 1;
		}
		else
		{
			int c = s[b].c, v = s[b].v;
			s[b].mn = v;
			s[b].c = s[b].sz = qr - s[left].sz - s[mid].sz;
			newnode(tmp);
			s[tmp].mode = 1;
			s[tmp].v = s[tmp].mn = v;
			s[tmp].sz = s[tmp].c = c - s[b].c;
		}
		mid = merge(mid, b);
		right = merge(tmp, right);
		lb:;
	}
	int query(int ql, int qr)
	{
		int left, mid, right;
		split(ql, qr, left, mid, right);
		int ret = s[mid].mn;
		rt = merge(merge(left, mid), right);
		return ret;
	}
	void modify(int ql, int qr, int val)
	{
		int left, mid, right;
		split(ql, qr, left, mid, right);
		newnode(mid);
		s[mid].mode = 1, s[mid].v = s[mid].mn = val;
		s[mid].sz = s[mid].c = qr - ql + 1;
		rt = merge(merge(left, mid), right);
	}
}tree;
int main()
{
	// freopen(".in", "r", stdin);
	// freopen(".out", "w", stdout);
	read(n, k);
	for(int i = 1; i <= n; i++) read(b[i]);
	ST.init(), tree.init();
	read(q);
	for(int i = 1, op, l, r, x; i <= q; i++)
	{
		read(op, l, r);
		if(op == 1) read(x), tree.modify(l, r, x);
		else printf("%d\n", tree.query(l, r));
	}
	return 0;
}
posted @ 2025-02-13 21:13  flyingpg  阅读(15)  评论(0)    收藏  举报