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;
}
posted @ 2022-10-19 17:57  zyy2001  阅读(24)  评论(0编辑  收藏  举报