珂朵莉樹學習筆記
阿新 • • 發佈:2019-02-07
long long int iterator print pow 要求 思路 數值 插入
為例。題目要求支持4種操作/詢問:
說真的,這數據結構這麽暴力,真的沒什麽好講的……
用途
在數據隨機、有區間覆蓋操作時:
用這種仿佛是暴力的算法爆踩線段樹、分塊等穩定算法。
解決求\(\sum a_i^k\)的區間詢問。
其他時候:
- 時間不夠或想不出正解時騙分。
- 對拍。
寫著玩
實現
思路
將一個序列分成若幹塊,每塊的數值相同,這樣可以快速修改/查詢。
把這些塊存在一個\(set\)裏。
有區間賦值操作時把這個區間中的所有塊刪除,然後插入這個區間。
其他時候暴力遍歷這個區間,暴力修改/查詢。
(是的,就是這麽暴力)
代碼
這裏以\(Codeforces \;896C \;Willem, Chtholly\; and \;Seniorious?\)
- 區間加\(x\)。
- 區間賦值為\(x\)。
- 區間第\(k\)小。
- 區間每個數的\(k\)次方和(即\(\sum_{i=l}^r a_i^k \pmod{y}\))。
保證數據隨機。
從定義開始:
struct miafi // 瞎敲的幾個字母 { int l,r; mutable ll v; const bool operator < (const miafi &a) const {return l<a.l;} miafi(int L,int R,ll V){l=L,r=R,v=V;} }; set<miafi>s; #define iter set<miafi>::iterator
\(l,r\)表示這個區間,\(v\)表示這個區間的值。註意\(\text{mutable}\)表示這個值即使在\(set\)中也是可變的。
重載運算符按左端點排序。
核心操作\(split\):把\(pos\)所在的區間分為\([l,pos-1],[pos,r]\),返回\([pos,r]\)的叠代器。
iter split(int pos) { iter i=s.lower_bound(miafi(pos,0,0)); if (i!=s.end()&&i->l==pos) return i; --i; int L=i->l,R=i->r;ll V=i->v; s.erase(i); s.insert(miafi(L,pos-1,V)); return s.insert(miafi(pos,R,V)).fir; }
註意下面要先\(split(r+1)\)然後再\(split(l)\),不然可能導致\(l\)的叠代器失效。
區間賦值操作:
void assign(int l,int r,ll v)
{
iter R=split(r+1),L=split(l);
s.erase(L,R);
s.insert(miafi(l,r,v));
}
下面的一個比一個暴力,直接放上來吧:
void add(int l,int r,ll v)
{
iter R=split(r+1),L=split(l);
for (iter i=L;i!=R;++i) i->v+=v;
}
ll kth(int l,int r,int k)
{
iter R=split(r+1),L=split(l);
vector<pli>vec;
for (iter i=L;i!=R;++i) vec.push_back(MP(i->v,i->r-i->l+1));
sort(vec.begin(),vec.end());
rep(i,0,(int)vec.size()-1) if ((k-=vec[i].sec)<=0) return vec[i].fir;
return -1;
}
ll kpow(int l,int r,int k,ll mod)
{
iter R=split(r+1),L=split(l);
ll ret=0;
for (iter i=L;i!=R;++i) (ret+=1ll*(i->r-i->l+1)*ksm(i->v%mod,k,mod)%mod)%=mod;
return ret;
}
完整代碼:
#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define pli pair<ll,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
typedef long long ll;
template<typename T>
inline void read(T& t)
{
t=0;char f=0,ch=getchar();
double d=0.1;
while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar();
while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar();
if(ch==‘.‘)
{
ch=getchar();
while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar();
}
t=(f?-t:t);
}
template<typename T,typename... Args>
inline void read(T& t,Args&... args){read(t); read(args...);}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.txt","r",stdin);
#endif
}
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
ll ksm(ll x,int y,ll mod)
{
ll ret=1;
for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;
return ret;
}
struct miafi
{
int l,r;
mutable ll v;
const bool operator < (const miafi &a) const {return l<a.l;}
miafi(int L,int R,ll V){l=L,r=R,v=V;}
};
set<miafi>s;
#define iter set<miafi>::iterator
iter split(int pos)
{
iter i=s.lower_bound(miafi(pos,0,0));
if (i!=s.end()&&i->l==pos) return i;
--i;
int L=i->l,R=i->r;ll V=i->v;
s.erase(i);
s.insert(miafi(L,pos-1,V));
return s.insert(miafi(pos,R,V)).fir;
}
void assign(int l,int r,ll v)
{
iter R=split(r+1),L=split(l);
s.erase(L,R);
s.insert(miafi(l,r,v));
}
void add(int l,int r,ll v)
{
iter R=split(r+1),L=split(l);
for (iter i=L;i!=R;++i) i->v+=v;
}
ll kth(int l,int r,int k)
{
iter R=split(r+1),L=split(l);
vector<pli>vec;
for (iter i=L;i!=R;++i) vec.push_back(MP(i->v,i->r-i->l+1));
sort(vec.begin(),vec.end());
rep(i,0,(int)vec.size()-1) if ((k-=vec[i].sec)<=0) return vec[i].fir;
return 666ll;
}
ll kpow(int l,int r,int k,ll mod)
{
iter R=split(r+1),L=split(l);
ll ret=0;
for (iter i=L;i!=R;++i) (ret+=1ll*(i->r-i->l+1)*ksm(i->v%mod,k,mod)%mod)%=mod;
return ret;
}
int n,m,seed,vmax;
inline int rnd()
{
int ret=seed;
seed=(7ll*seed+13)%1000000007;
return ret;
}
int main()
{
file();
int op,l,r,x,y;
read(n,m,seed,vmax);
rep(i,1,n) s.insert(miafi(i,i,rnd()%vmax+1));
while (m--)
{
op=(rnd()%4)+1,l=(rnd()%n)+1,r=(rnd()%n)+1;
if (l>r) swap(l,r);
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);
if (op==2) assign(l,r,x);
if (op==3) printf("%lld\n",kth(l,r,x));
if (op==4) printf("%lld\n",kpow(l,r,x,y));
}
}
雖然看起來很暴力,但數據隨機時期望復雜度\(O(n\log n)?\)。(也許不是?反正能過就對了)
例題
\(Codeforces \;896C \;Willem, Chtholly\; and \;Seniorious\)
\(Codeforces\; 915E\; Physical \;Education \;Lessons\)(雖然不保證隨機但仍然爆踩\(std\))
珂朵莉樹學習筆記