【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;
}