CF896C Willem, Chtholly and Seniorious

Link

Difficulty

算法难度6,思维难度5,代码难度5

Description

维护一个数列,支持四种操作:

  1. L R x ,给区间[L,R]加上x
  2. L R x ,讲区间[L,R]都变成x
  3. L R k ,询问区间[L,R]的第k小数
  4. L R x y ,询问区间[L,R]的x次幂和,对y取模

1 ≤ n , m ≤ 1 0 5 , 1 ≤ a i ≤ 1 0 9 1\le n,m\le 10^5,1\le a_i\le 10^9 1n,m105,1ai109

保证数据随机生成。

Solution

这题的科技叫珂朵莉树,或者叫ODT(Old Driver Tree)。

珂朵莉树能用来维护一类带有区间修改成某一值的操作的题,但是前提是数据随机。

大体思路就是用set来维护连续极长的相同区间。

可以证明在随机数据下,连续极长的相同区间个数是 O ( l o g n ) O(logn) O(logn)级别的。

于是我们用暴力维护的复杂度就是 O ( m l o g n ) O(mlogn) O(mlogn)级别的。

具体写法上有几个注意的地方:

  1. 在set中要修改值的话,需要在结构体声明时对该变量加上修饰词mutable,意为多变的,可变的。
  2. set的erase可以指定两个迭代器,删除两个迭代器之间的全部元素(左闭右开)
  3. 数据生成部分是要开long long的。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#define LL long long
using namespace std;
inline int read(){
	int x=0,f=1;char ch=' ';
	while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f==1?x:-x;
}
const int N=1e5+5,mod=1e9+7;
struct node{
	int l,r;
	mutable LL v;
	node(int L,int R,LL V):l(L),r(R),v(V){}
	inline bool operator < (const node& b) const {return l<b.l;}
};
set<node> s;
int n,m;
LL a[N],seed,vmax;
inline LL Rand(){
	LL ret=seed;
	seed=(seed*7+13)%mod;
	return ret;
}
inline LL ksm(LL a,LL n,LL p){
	LL ans=1LL;a%=p;
	while(n){
		if(n&1)ans=ans*a%p;
		a=a*a%p;
		n>>=1;
	}
	return ans;
}
typedef set<node>::iterator IT;
inline IT split(int pos){
	IT it=s.lower_bound(node(pos,pos,1));
	if(it!=s.end() && it->l==pos)return it;
	--it;
	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;
}
inline void add(int l,int r,LL v){
	IT it1=split(l),it2=split(r+1);
	for(;it1!=it2;++it1)it1->v+=v;
}
inline void assign(int l,int r,LL v){
	IT it1=split(l),it2=split(r+1);
	s.erase(it1,it2);
	s.insert(node(l,r,v));
}
inline void Rank(int l,int r,int k){
	IT it1=split(l),it2=split(r+1);
	vector<pair<LL,int> > t;
	for(;it1!=it2;++it1)t.push_back(pair<LL,int>(it1->v,it1->r-it1->l+1));
	sort(t.begin(),t.end());
	LL ans=0;
	for(vector<pair<LL,int> >::iterator it=t.begin();it!=t.end();++it){
		if(k<=it->second){ans=it->first;break;}
		else k-=it->second;
	}
	printf("%lld\n",ans);
}
inline void sum(int l,int r,int x,int p){
	IT it1=split(l),it2=split(r+1);
	LL ans=0;
	for(;it1!=it2;++it1)ans=(ans+(LL)(it1->r-it1->l+1)*ksm(it1->v,x,p))%p;
	printf("%lld\n",ans);
}
int main(){
	n=read();m=read();seed=read();vmax=read();
	for(int i=1;i<=n;++i){
		a[i]=Rand()%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 opt=Rand()%4+1;
		int l=Rand()%n+1;
		int r=Rand()%n+1;
		if(l>r)swap(l,r);
		int x=0,y=0;
		if(opt==3)x=Rand()%(r-l+1)+1;
		else x=Rand()%vmax+1;
		if(opt==4)y=Rand()%vmax+1;
		if(opt==1)add(l,r,x);
		else if(opt==2)assign(l,r,x);
		else if(opt==3)Rank(l,r,x);
		else sum(l,r,x,y);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值