好文章
LUOGU
個人理解:珂朵莉樹其實就是\(set\)大法,就是暴力,可以構造特殊資料卡掉,但是在隨機資料的情況下,它是非常快的
struct ASD
{
ll l,r;
mutable ll val;//方便更改,指標是常量,必須加上mutable
bool operator < (const ASD& A)const
{
return l<A.l;
}
ASD(ll a,ll b,ll c)
{
l=a;r=b;val=c;
}
ASD(ll a)
{
l=a;
}
};
#define sit set<ASD>::iterator//懶人
分裂操作,將一個區間中的一個位置分裂成\([l,pos],[pos+1,r]\),是核心步驟,以後都是圍繞他進行的
set<ASD> s;
sit split(ll pos)
{
sit it=s.lower_bound(ASD(pos));
if(it!=s.end()&&(*it).l==pos)return it;
it--;
ll l=(*it).l,r=(*it).r,val=(*it).val;
s.erase(it);
s.insert(ASD(l,pos-1,val));//注意邊界啊,以後要用到
return s.insert(ASD(pos,r,val)).first;//first返回迭代器,second返回值
}
區間推平,很暴力,一定要先找\(r+1\),再找&l&,否則位置會改變,\(RE\)
void assign(ll l,ll r,ll val)
{
sit it2=split(r+1),it1=split(l);
//刪除區間[l,r+1)中所有的節點,注意左閉右開
s.erase(it1,it2);
s.insert(ASD(l,r,val));
}
同理,區間加
void add(ll l,ll r,ll val)
{
sit it2=split(r+1),it1=split(l);
for(sit it=it1;it!=it2;it++)
{
(*it).val+=val;
}
}
查詢第\(k\)小
ll kth(ll l,ll r,ll k)
{
sit it2=split(r+1),it1=split(l);
vector <pair<ll,ll>> a;
a.clear();
for(sit it=it1;it!=it2;it++)
{
a.push_back({(*it).val,(*it).r-(*it).l+1});
}
sort(a.begin(),a.end());//排個序就行了,真暴力
for(ull i=0;i<a.size();i++)
{
k-=a[i].second;
if(k<=0)return a[i].first;
}
// return 0;
}
簡單封一封
#define sit set<ASD>::iterator
struct ASD
{
ll l,r;
mutable ll val;
bool operator < (const ASD& A)const
{
return l<A.l;
}
ASD(ll a,ll b,ll c)
{
l=a;r=b;val=c;
}
ASD(ll a)
{
l=a;
}
};
struct ODT
{
set<ASD> s;
sit split(ll pos)
{
sit it=s.lower_bound(ASD(pos));
if(it!=s.end()&&(*it).l==pos)return it;
it--;
ll l=(*it).l,r=(*it).r,val=(*it).val;
s.erase(it);
s.insert(ASD(l,pos-1,val));
return s.insert(ASD(pos,r,val)).first;
}
void assign(ll l,ll r,ll val)
{
sit it2=split(r+1),it1=split(l);
s.erase(it1,it2);
s.insert(ASD(l,r,val));
}
void add(ll l,ll r,ll val)
{
sit it2=split(r+1),it1=split(l);
for(sit it=it1;it!=it2;it++)
{
(*it).val+=val;
}
}
ll kth(ll l,ll r,ll k)
{
sit it2=split(r+1),it1=split(l);
vector <pair<ll,ll>> a;
a.clear();
for(sit it=it1;it!=it2;it++)
{
a.push_back({(*it).val,(*it).r-(*it).l+1});
}
sort(a.begin(),a.end());
for(ull i=0;i<a.size();i++)
{
k-=a[i].second;
if(k<=0)return a[i].first;
}
// return 0;
}
ll cx(ll l ,ll r,ll x,ll mod)
{
sit it2=split(r+1),it1=split(l);
ll ans=0;
for(sit it=it1;it!=it2;it++)
{
ans=(ans+((*it).r-(*it).l+1)*qpow((*it).val,x,mod)%mod)%mod;
}
return ans;
}
}odt;
例題
[模板CF896C]
點選檢視程式碼
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
ll qpow(ll a,ll b,ll mod)
{
ll ans=1;
a%=mod;//一定要有,CF不讓用__int128
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
#define sit set<ASD>::iterator
struct ASD
{
ll l,r;
mutable ll val;
bool operator < (const ASD& A)const
{
return l<A.l;
}
ASD(ll a,ll b,ll c)
{
l=a;r=b;val=c;
}
ASD(ll a)
{
l=a;
}
};
struct ODT
{
set<ASD> s;
sit split(ll pos)
{
sit it=s.lower_bound(ASD(pos));
if(it!=s.end()&&(*it).l==pos)return it;
it--;
ll l=(*it).l,r=(*it).r,val=(*it).val;
s.erase(it);
s.insert(ASD(l,pos-1,val));
return s.insert(ASD(pos,r,val)).first;
}
void assign(ll l,ll r,ll val)
{
sit it2=split(r+1),it1=split(l);
s.erase(it1,it2);
s.insert(ASD(l,r,val));
}
void add(ll l,ll r,ll val)
{
sit it2=split(r+1),it1=split(l);
for(sit it=it1;it!=it2;it++)
{
(*it).val+=val;
}
}
ll kth(ll l,ll r,ll k)
{
sit it2=split(r+1),it1=split(l);
vector <pair<ll,ll>> a;
a.clear();
for(sit it=it1;it!=it2;it++)
{
a.push_back({(*it).val,(*it).r-(*it).l+1});
}
sort(a.begin(),a.end());
for(ull i=0;i<a.size();i++)
{
k-=a[i].second;
if(k<=0)return a[i].first;
}
// return 0;
}
ll cx(ll l ,ll r,ll x,ll mod)
{
sit it2=split(r+1),it1=split(l);
ll ans=0;
for(sit it=it1;it!=it2;it++)
{
ans=(ans+((*it).r-(*it).l+1)*qpow((*it).val,x,mod)%mod)%mod;
}
return ans;
}
}odt;
const int N = 1e5+5;
ll n,m,seed,vmax,a[N];
ll rnd()
{
ll ret = seed;
seed = (seed * 7 + 13)%1000000007;
return ret;
}
int main ()
{
speed();
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
cin>>n>>m>>seed>>vmax;
// cout<<n<<endl;
for(int i=1;i<=n;i++)
{
a[i]=(rnd()%vmax)+1;
odt.s.insert(ASD(i,i,a[i]));
}
// cout<<"******"<<endl;
ll op,l,r,x,y;
for(int i=1;i<=m;i++)
{
// cout<<i<<endl;
op=(rnd()%4)+1;
// cout<<op<<endl;
l=(rnd()%n)+1;
r=(rnd()%n)+1;
if(l>r)swap(l,r);
if(op==3)
{
x=rnd()%(r-l+1)+1;
cout<<odt.kth(l,r,x)<<endl;
}else
{
x=rnd()%vmax+1;
}
if(op==1)
{
// cout<<i<<endl;
odt.add(l,r,x);
}
if(op==2)odt.assign(l,r,x);
if(op==4)
{
y=rnd()%vmax+1;
cout<<odt.cx(l,r,x,y)<<endl;
}
// cout<<"*******"<<endl;
}
return 0;
}