珂朵莉树

Posted emcikem

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了珂朵莉树相关的知识,希望对你有一定的参考价值。

  • 将一段区间的值全变成c
  • 区间加
  • 区间第k小的数
  • 区间幂次和
    传送门

    模板

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <algorithm>
#define IT set<node>::iterator
using namespace std;
const int maxn = 1e5+5;
const int inf = 0x3f3f3f3f;
const int mod7 = 1e9+7;
typedef long long ll;
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
struct node{
    int l,r;//范围
    mutable ll v;//数值
    node(int L,int R=-1,ll V=0):l(L),r(R),v(V){}
    bool operator<(const node& o)const{//重载运算符,以左端点升序
        return l < o.l;
    }
};
set<node>s;
IT split(int pos){
    IT it = s.lower_bound(node(pos));//找到首个不小于pos的set
    if(it!=s.end()&&it->l==pos)return it;

    it--;
    int L = it->l,R = it->r;//要分裂的区间[l,r]
    ll V = it->v;
    s.erase(it);//删除原集合
    s.insert(node(L,pos-1,V));//构成前半段的新结合
    return s.insert(node(pos,R,V)).first;//构成后半段的新集合,并返回地址
}
void assign_val(int l,int r,ll val){//区间推平
    IT itl = split(l),itr = split(r+1);//求出要被摊平区间的收尾地址
    s.erase(itl,itr);
    s.insert(node(l,r,val));
}
void add(int l,int r,ll val){//区间加
    IT itl = split(l),itr = split(r+1);
    for(;itl!=itr;itl++){
        itl->v+=val;
    }
}
ll Rank(int l,int r,int k){//区间第k小
    vector<pair<ll,int> > vp;
    IT itl = split(l),itr = split(r+1);
    vp.clear();
    for(;itr!=itl;itl++){
        vp.push_back(pair<ll,int >(itl->v,itl->r-itl->l+1));
    }
    sort(vp.begin(),vp.end());
    vector<pair<ll,int > >::iterator it;
    for(it=vp.begin();it!=vp.end();it++){
        k -= it->second;
        if(k<=0)return it->first;
    }
    return 0;
}
ll pow(ll a,ll b,ll p){
    ll ans = 1;
    a = a%p;
    while(b){
        if(b&1)ans=ans*a%p;
        b>>=1;
        a = a*a%p;
    }
    return ans;
}
ll sum(int l,int r,int ex,int p){
    IT itl = split(l),itr = split(r+1);
    ll ans = 0;
    for(;itr!=itl;itl++){
        ans = (ans + (ll)(itl->r - itl->l + 1) * pow(itl->v,ll(ex), ll(p))) % p;
    }
    return ans;
}
ll seed,vmax;
ll a[maxn];
ll rnd(){
    ll ret = seed;
    seed = (seed*7+13)%mod7;
    return ret;
}
int main(){
    int n = read(),m = read();
    cin>>seed>>vmax;
    for(int i=1;i<=n;i++){
        a[i] = rnd()%vmax+1;
        s.insert(node(i,i,a[i]));
    }
    s.insert(node(n+1,n+1,0));
    int lines = 0;
    for(int i=1;i<=m;i++){
        int op = int(rnd()%4)+1;
        int l = int(rnd()%n)+1;
        int r = int(rnd()%n)+1;
        if(l>r)swap(l,r);
        int x,y;
        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,ll(x));
        else if(op==2)assign_val(l,r,ll(x));
        else if(op==3)cout<<Rank(l,r,x)<<endl;
        else cout<<sum(l,r,x,y)<<endl;
    }

    return 0;
}

以上是关于珂朵莉树的主要内容,如果未能解决你的问题,请参考以下文章

珂朵莉树(ODT老司机树)

模板—珂朵莉树

P2787 语文1(chin1)- 理理思维(珂朵莉树)

CF896C Willem, Chtholly and Seniorious 珂朵莉树

hdu4578线段树维护平方和,立方和(加,乘,赋值)或者珂朵莉树

LG4979 矿洞:坍塌 珂朵莉树