[模板] ODT-老司机树 CodeForces-896C
[模板] ODT-老司机树 CodeForces-896C
适用于随机数据 ,区间赋值。
核心思想,把值相同的区间合并成一个结点保存在set里。
结点保存
struct node {
int l, r;
mutable ll v;
node(int _l,int _r = -1,ll _v = 0):l(_l),r(_r),v(_v){}
bool operator < (const node& b) const {
return l < b.l;
}
};
mutable 的含义是“可变的”,让我们可以在后续操作中修改v的值。
这意味着我们可以直接修改以及插入的set的元素的v值,而不用将元素取出再插入
核心操作
split
它用于将原本包含点x的区间\([l,r]\) 分裂为两个区间\([l,x),[x,r]\) 并且返回后者的迭代器
auto split(int pos) {
auto it = s.lower_bound(node(pos));
if (it != s.end() && it->l == pos) return it;
--it;
if (pos > it->r) return s.end();
int L = it->l, R = it->r;
ll V = it->v;
s.erase(it);
s.insert(node(L, pos - 1, V));
return s.insert(node(pos, R, V)).first;
}
assign
可以使ODT的大小大大减小
void assign(int l, int r, ll val = 0) {
auto itr = split(r + 1), itl = split(l);
s.erase(itl, itr);
s.insert(node(l, r, val));
}
其他
套模板就好了
代码
struct node {
int l, r;
mutable ll v;
node(int _l,int _r = -1,ll _v = 0):l(_l),r(_r),v(_v){}
bool operator < (const node& b) const {
return l < b.l;
}
};
set<node> s;
vector<pii> v;
auto split(int pos) {
auto it = s.lower_bound(node(pos));
if (it != s.end() && it->l == pos) return it;
--it;
if (pos > it->r) return s.end();
int L = it->l, R = it->r;
ll V = it->v;
s.erase(it);
s.insert(node(L, pos - 1, V));
return s.insert(node(pos, R, V)).first;
}
void add(int l, int r, ll val = 1) {
auto itr = split(r + 1), itl = split(l);
for (; itl != itr; itl++) itl->v += val;
}
void assign(int l, int r, ll val = 0) {
auto itr = split(r + 1), itl = split(l);
s.erase(itl, itr);
s.insert(node(l, r, val));
}
ll get_rank(int l, int r, int k, bool reversed = 0) {
if (reversed) k = r - l + 2 - k;
auto itr = split(r + 1), itl = split(l);
v.clear();
for (; itl != itr; itl++)
v.push_back(make_pair(itl->v, itl->r - itl->l + 1));
sort(v.begin(), v.end());
for (auto i : v) {
k -= i.second;
if (k <= 0) return i.first;
}
return -1;
}
ll sum(int l, int r, int ex, int mod) {
auto itr = split(r + 1), itl = split(l);
ll res = 0;
for (; itl != itr; itl++)
res += (ll)(itl->r - itl->l + 1) % mod * ksm(itl->v,(ll) ex,(ll) mod) % mod, res %= mod;
return res;
}
int n, m;
ll seed, vm;
ll rad() {
ll res = seed;
seed = (seed * 7 + 13) % 1000000007;
return res;
}
int main() {
int op, l, r;
int x, y;
n = readint(), m = readint(), seed = readll(), vm = readll();
for (int i = 1; i <= n; i++) {
ll tmp = (rad() % vm) + 1;
s.insert(node(i, i, tmp));
}
while (m--) {
op = (rad() % 4) + 1;
l = (rad() % n) + 1;
r = (rad() % n) + 1;
if (l > r) swap(l, r);
if (op == 3) x = (rad() % (r - l + 1)) + 1;
else x = (rad() % vm) + 1;
if (op == 4) y = (rad() % vm) + 1;
if (op == 1) add(l, r, x);
else if (op == 2) assign(l, r, x);
else if (op == 3) Put(get_rank(l, r, x)), uts("");
else {
Put(sum(l, r, x, y)), puts("");
}
}
}