1. 程式人生 > >珂朵莉樹學習筆記

珂朵莉樹學習筆記

long long int iterator print pow 要求 思路 數值 插入

說真的,這數據結構這麽暴力,真的沒什麽好講的……


用途

數據隨機有區間覆蓋操作時:

  • 用這種仿佛是暴力的算法爆踩線段樹、分塊等穩定算法。

  • 解決求\(\sum a_i^k\)的區間詢問。

其他時候:

  • 時間不夠或想不出正解時騙分。
  • 對拍。
  • 寫著玩

實現

思路

將一個序列分成若幹塊,每塊的數值相同,這樣可以快速修改/查詢。

把這些塊存在一個\(set\)裏。

有區間賦值操作時把這個區間中的所有塊刪除,然後插入這個區間。

其他時候暴力遍歷這個區間,暴力修改/查詢。

(是的,就是這麽暴力)

 代碼

這裏以\(Codeforces \;896C \;Willem, Chtholly\; and \;Seniorious?\)

為例。題目要求支持4種操作/詢問:

  1. 區間加\(x\)
  2. 區間賦值為\(x\)
  3. 區間第\(k\)小。
  4. 區間每個數的\(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\)

珂朵莉樹學習筆記