ODT是个美妙有暴力的东西
大体思想是用一个 set 维护一段一段的区间,比如
struct Node{int l, r, v;};
set<Node> S;
适用范围就是有区间赋值操作,因为这个操作可以大大缩小set的空间
然后又个核心的 Split 操作,把一个区间分成两个,大概就是lower_bound一下左端点然后删除区间再插入两个区间
还有一个比较核心的就是 Assign(区间赋值) ,我们把 l -- r 之间的 set 全部删掉,在插一个进去就可以了
其余全是暴力
#include<bits/stdc++.h>
#define N 100050
using namespace std;
typedef long long ll;
int n, m; ll seed, vmax, a[N];
ll rnd(){
ll ret = seed;
seed = (7 * seed + 13) % 1000000007;
return ret;
}
struct Node{
int l, r; mutable ll val;
Node(int _l, int _r = -1, ll v=0):l(_l), r(_r), val(v){};
bool operator < (const Node &a) const {
return l < a.l;
}
}; set<Node> S;
typedef set<Node>::iterator It;
It Split(int pos){
It it = S.lower_bound(Node(pos));
if(it != S.end() && it->l == pos) return it;
--it;
int L = it->l, R = it->r; ll val = it->val;
S.erase(it); S.insert(Node(L, pos-1, val));
return S.insert(Node(pos, R, val)).first;
}
void Add(int l, int r, ll x){
It it1 = Split(l), it2 = Split(r+1);
for(;it1 != it2; ++it1) it1->val += x;
}
void Assign(int l, int r, ll x){
It it1 = Split(l), it2 = Split(r+1);
S.erase(it1, it2); S.insert(Node(l, r, x));
}
ll add(ll a, ll b, ll c){ return (a+b) % c;}
ll mul(ll a, ll b, ll c){ a %= c, b %= c; return (a*b) % c;}
ll power(ll a, ll b, ll c){
ll ans = 1; a %= c;
for(;b;b>>=1){ if(b&1) ans = mul(ans, a, c); a = mul(a, a, c);} return ans;
}
#define mp make_pair
ll Rank(int l, int r, int k){
vector<pair<ll, int> > v; v.clear();
It it1 = Split(l), it2 = Split(r+1);
for(;it1 != it2; ++it1) v.push_back(mp(it1->val, it1->r - it1->l + 1));
sort(v.begin(), v.end());
for(int i=0; i<v.size(); i++){
k -= v[i].second;
if(k <= 0) return v[i].first;
} return -1;
}
ll Ask(int l, int r, ll x, ll y){
It it1 = Split(l), it2 = Split(r+1);
ll ans = 0;
for(;it1 != it2; ++it1) ans = add(ans, mul(it1->r - it1->l + 1, power(it1->val, x, y), y), y);
return ans;
}
int main(){
scanf("%d%d%d%d", &n, &m, &seed, &vmax);
for(int i=1; i<=n; i++){
a[i] = (rnd() % vmax) + 1;
S.insert(Node(i, i, a[i]));
} S.insert(Node(n+1, n+1, 0));
for(int i=1; i<=m; i++){
int op = (rnd() % 4) + 1;
int l = (rnd() % n) + 1;
int r = (rnd() % n) + 1;
if(l > r) swap(l, r);
ll x;
if(op == 3) x = (rnd() % (r - l + 1)) + 1;
else x = (rnd() % vmax) + 1;
if(op == 1) Add(l, r, x);
if(op == 2) Assign(l, r, x);
if(op == 3) printf("%lld\n", Rank(l, r, x));
if(op == 4){
ll y = (rnd() % vmax) + 1;
printf("%lld\n", Ask(l, r, x, y));
}
} return 0;
}