算法难度6,思维难度5,代码难度5
维护一个数列,支持四种操作:
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 1≤n,m≤105,1≤ai≤109
保证数据随机生成。
这题的科技叫珂朵莉树,或者叫ODT(Old Driver Tree)。
珂朵莉树能用来维护一类带有区间修改成某一值的操作的题,但是前提是数据随机。
大体思路就是用set来维护连续极长的相同区间。
可以证明在随机数据下,连续极长的相同区间个数是 O ( l o g n ) O(logn) O(logn)级别的。
于是我们用暴力维护的复杂度就是 O ( m l o g n ) O(mlogn) O(mlogn)级别的。
具体写法上有几个注意的地方:
#include
#include
#include
#include
#include
#include
#include
#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;
}