CF896C Willem, Chtholly and Seniorious [ODT]

传送门

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值