CF896C Willem, Chtholly and Seniorious
题目链接
CF896C Willem, Chtholly and Seniorious
【题面】
请你写一种奇怪的数据结构,支持:
- \(1\) \(l\) \(r\) \(x\) :将\([l,r]\) 区间所有数加上\(x\)
- \(2\) \(l\) \(r\) \(x\) :将\([l,r]\) 区间所有数改成\(x\)
- \(3\) \(l\) \(r\) \(x\) :输出将\([l,r]\) 区间从小到大排序后的第\(x\) 个数是的多少(即区间第\(x\) 小,数字大小相同算多次,保证 \(1\leq\) \(x\) \(\leq\) \(r-l+1\) )
- \(4\) \(l\) \(r\) \(x\) \(y\) :输出\([l,r]\) 区间每个数字的\(x\) 次方的和模\(y\) 的值(即(\(\sum^r_{i=l}a_i^x\) ) \(\mod y\) )
【输入格式】
这道题目的输入格式比较特殊,需要选手通过\(seed\) 自己生成输入数据。
输入一行四个整数\(n,m,seed,v_{max}\) ($1\leq $ \(n,m\leq 10^{5}\) ,\(0\leq seed \leq 10^{9}+7\) $,1\leq vmax \leq 10^{9} $ )
其中\(n\) 表示数列长度,\(m\) 表示操作次数,后面两个用于生成输入数据。
数据生成的伪代码如下
def rnd():
ret = seed
seed = (seed * 7 + 13) mod 1000000007
return ret
for i = 1 to n:
a[i] = (rnd() mod vmax) + 1
for i = 1 to m:
op = (rnd() mod 4) + 1
l = (rnd() mod n) + 1
r = (rnd() mod n) + 1
if (l > r):
swap(l, r)
if (op == 3):
x = (rnd() mod (r - l + 1)) + 1
else:
x = (rnd() mod vmax) + 1
if (op == 4):
y = (rnd() mod vmax) + 1
其中上面的op指题面中提到的四个操作。
【输出格式】
对于每个操作3和4,输出一行仅一个数。
解题思路
珂朵莉树
珂朵莉树是一种优雅的暴力,常用来解决数据随机且带有区间赋值操作的问题
核心思想在于将值相等的区间合并为一个节点保存在 set
中,同时还有一个关键函数 \(split(x)\),表示将含有 \(x\) 的区间 \([l,r]\) 分为 \([l,x-1],[x,r]\) 两个区间,同时返回后者,所以对于区间 \([l,r]\),可以分为 \([split(l),split(r+1))\) 这些 set
上的节点,其他操作据此暴力计算或修改即可
注意分区间的时候先 \(split(r+1)\) 然后 \(split(l)\)
- 时间复杂度:\(O(mlog^2n)\)
代码
// Problem: C. Willem, Chtholly and Seniorious
// Contest: Codeforces - Codeforces Round #449 (Div. 1)
// URL: https://codeforces.com/contest/896/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
// #define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int mod=1e9+7;
int n,m,seed,vmax;
struct odt
{
int l,r;
mutable LL v;
odt(const int &_l,const int &_r,const LL &_v):l(_l),r(_r),v(_v){}
inline bool operator<(const odt &o)const
{
return l<o.l;
}
};
set<odt> s;
int rnd()
{
int res=seed;
seed=(1ll*seed*7+13)%mod;
return res;
}
auto split(int x)
{
auto it=--s.upper_bound({x,0,0});
if(it->l==x)return it;
int l=it->l,r=it->r;
LL v=it->v;
s.erase(it);
s.insert({l,x-1,v});
return s.insert({x,r,v}).fi;
}
void add(int l,int r,int x)
{
auto itr=split(r+1),itl=split(l);
while(itl!=itr)itl->v+=x,itl++;
}
void assign(int l,int r,int v)
{
auto itr=split(r+1),itl=split(l);
s.erase(itl,itr);
s.insert({l,r,v});
}
LL ask_kth(int l,int r,int k)
{
auto itr=split(r+1),itl=split(l);
vector<pair<LL,int>> a;
while(itl!=itr)
{
a.pb({itl->v,itl->r-itl->l+1});
itl++;
}
sort(a.begin(),a.end());
for(auto t:a)
{
k-=t.se;
if(k<=0)return t.fi;
}
return -1;
}
int ksm(LL a,int b,int p)
{
int res=1%p;
a%=p;
while(b)
{
if(b&1)res=1ll*res*a%p;
a=1ll*a*a%p;
b>>=1;
}
return res;
}
int ask_sum(int l,int r,int x,int y)
{
auto itr=split(r+1),itl=split(l);
int res=0;
while(itl!=itr)
{
res=(1ll*res+1ll*ksm(itl->v,x,y)*(itl->r-itl->l+1))%y;
itl++;
}
return res;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&seed,&vmax);
for(int i=1;i<=n;i++)s.insert({i,i,rnd()%vmax+1});
while(m--)
{
int op=rnd()%4+1;
int l=rnd()%n+1,r=rnd()%n+1;
if(l>r)swap(l,r);
int x,y;
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);
else if(op==2)assign(l,r,x);
else if(op==3)
printf("%lld\n",ask_kth(l,r,x));
else
printf("%d\n",ask_sum(l,r,x,y));
}
return 0;
}