【luogu CF896C】Willem, Chtholly and Seniorious(珂朵莉树)

Willem, Chtholly and Seniorious

题目链接:luogu CF896C

题目大意

要你维护一个数组,会有区间加值,区间赋值,求区间第 x 小,求区间每个数的 x 次方和模 y 结果。

思路

这题是珂朵莉树的模板题。

首先珂朵莉树并不是树,它可以说是一种暴力的方法,来解决一种区间赋同一个值然后维护的问题。
(然后根据情况有一些维护需要数据随机有一些又不用)

大概就是你考虑把相同的数合并起来,用一个区间来表示。
然后你改的时候显然要两种操作,合并和分裂。

先说分裂,我们要 \([l,r]\) 变成 \([l,mid-1],[mid,r]\),可以用 lower_bound 找到这个区间先,然后如果 \(mid\) 就是区间左边 \(l\) 就不用分裂。
然后是合并,你就通过分裂 \(r+1,l\) 得到两边的区间,然后就直接用 erase 进行区间删除把那些都删了,然后加上新的串即可。
(然后注意要先分裂 \(r+1\) 再分裂 \(l\) 否则会可能出现 RE)

然后别的操作大概都是暴力枚举区间做即可。

代码

#include<set>
#include<cstdio>
#include<vector>
#include<algorithm>
#define ll long long
#define mo 1000000007

using namespace std;

ll n, m, seed, vmax, a[100001];

ll rnd (){
	ll re = seed;
	seed = (seed * 7 + 13) % mo;
	return re;
}

struct node {
	ll l, r;
	mutable ll v;
	
	bool operator <(const node &a) const {
		return l < a.l;
	}
};
set <node> s;

set <node> ::iterator split(int pl) {
	set <node> ::iterator it = s.lower_bound((node){pl, 0, 0});
	if (it != s.end() && (*it).l == pl) return it;
	it--;
	if ((*it).r < pl) return s.end();
	ll l = (*it).l, r = (*it).r, v = (*it).v;
	s.erase(it); s.insert((node){l, pl - 1, v});
	return s.insert((node){pl, r, v}).first;
}

//提取区间一定要先分裂右边再分裂左边,不然可能你到到时分裂的后边已经是被删除的,然后就会报错
void assign(ll l, ll r, ll x) {
	set <node> ::iterator itr = split(r + 1), itl = split(l);
	s.erase(itl, itr); s.insert((node){l, r, x});
}

void add(ll l, ll r, ll x) {
	set <node> ::iterator itr = split(r + 1), itl = split(l);
	for (set <node> ::iterator it = itl; it != itr; it++) {
		(*it).v += x;
	}
}

struct Rank {
	ll num, cnt;
	
	bool operator <(const Rank &to) const {
		return num < to.num;
	}
};

ll rnk(ll l, ll r, ll x) {
	set <node> ::iterator itr = split(r + 1), itl = split(l);
	vector <Rank> v;
	for (set <node> ::iterator it = itl; it != itr; it++) {
		v.push_back((Rank){(*it).v, (*it).r - (*it).l + 1});
	}
	sort(v.begin(), v.end());
	for (int i = 0 ; i < v.size(); i++) {
		if (x <= v[i].cnt) return v[i].num;
		x -= v[i].cnt;
	}
}

ll ksm(ll x, ll y, ll p) {
	ll re = 1; x %= p;
	while (y) {
		if (y & 1) re = re * x % p;
		x = x * x % p; y >>= 1;
	}
	return re;
}

ll clacp(ll l, ll r, ll x, ll y) {
	set <node> ::iterator itr = split(r + 1), itl = split(l);
	ll ans = 0;
	for (set <node> ::iterator it = itl; it != itr; it++) {
		ans = (ans + ksm((*it).v, x, y) * ((*it).r - (*it).l + 1) % y) % y;
	}
	return ans;
}

int main() {
	scanf("%lld %lld %lld %lld", &n, &m, &seed, &vmax);
	for (int i = 1; i <= n; i++) {
		a[i] = rnd() % vmax + 1;
		s.insert((node){i, i, a[i]});
	}
	
	for (int i = 1; i <= m; i++) {
		int op = rnd() % 4 + 1; 
		int l = rnd() % n + 1, r = rnd() % n + 1;
		int x, y;
		if (l > r) swap(l, r);
		if (op == 3) {
			x = rnd() % (r - l + 1) + 1;
		}
		else x = rnd() % vmax + 1;
		if (op == 4) y = rnd() % vmax + 1;
		
		if (op == 1) add(l, r, x);
		if (op == 2) assign(l, r, x);
		if (op == 3) printf("%lld\n", rnk(l, r, x));
		if (op == 4) printf("%lld\n", clacp(l, r, x, y));
	}
	
	return 0;
}
上一篇:Mysql中文乱码问题的解决办法


下一篇:秒杀功能