Solution: 题解 CF896C Willem, Chtholly and Seniorious(线段树解珂朵莉树)

Posted brianpeng

tags:

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

Intro:

珂朵莉树模板题

怎么所有题解都是珂朵莉树啊啊啊啊

于是本蒟蒻决定来一发中(feng)规(kuang)中(luan)矩(gao)的线段树

首先这棵线段树只维护懒标记

来一发定义

线段树节点(u)维护区间([l_u,r_u])的内容

懒标记(t_u):当(t_u ot=0)时表示区间([l_u,r_u])全是(t_u)(t_u=0)就是没有懒标记


建立线段树

在建立时顺便处理(l_u,r_u),只要当(l_u=r_u)时就打上标记

P.s (Ls=2u,Rs=2u+1)

void bld(int u){
    if(t[u].l==t[u].r){t[u].v=rnd()%vmx+1;return;}
    t[Ls].l=t[u].l,t[Rs].l=(t[Ls].r=(t[u].l+t[u].r)>>1)+1,t[Rs].r=t[u].r;
    bld(Ls),bld(Rs);
}

区间加

找到所有被覆盖且有标记的区间,让(t_u)加上(x)

P.s Don‘t forget pushdown().

void pd(int u){if(t[u].v)t[Ls].v=t[Rs].v=t[u].v,t[u].v=0;}
void mdfa(int u){
    if(r<t[u].l||t[u].r<l)return;
    if(l<=t[u].l&&t[u].r<=r&&t[u].v)t[u].v+=x;
    else pd(u),mdfa(Ls),mdfa(Rs);
}

区间设置

与一般懒标记操作最为类似,找到覆盖区间,打上标记即可

void mdfs(int u){
    if(r<t[u].l||t[u].r<l)return;
    if(l<=t[u].l&&t[u].r<=r)t[u].v=x;
    else pd(u),mdfs(Ls),mdfs(Rs);
}

区间查询

在这里我们借助一个 vector

struct Q{int v,s;};
vector<Q>q;

其中(v)表示区间值,(s)表示区间长度

首先把所有有交集且有标记的区间全部存到这个 vector 里(注意(s)的处理)

void qry(int u){
    if(r<t[u].l||t[u].r<l)return;
    if(t[u].v)q.push_back({t[u].v,min(t[u].r,r)-max(t[u].l,l)+1});
    else qry(Ls),qry(Rs);
}

那么对于区间第(x)小,将(q)(v)排序,然后暴力即可 (vector 真好用)

q.clear(),qry(1);
sort(q.begin(),q.end(),[](Q a,Q b){return a.v<b.v;});
for(Q i:q){
    if(x<=i.s){wr(i.v),Pe;break;}
    x-=i.s;
}

对于区间幂次和,排序都不用了,直接暴扫 (这么感觉和珂朵莉树一副德行)

ans=0,y=rnd()%vmx+1,q.clear(),qry(1);
for(Q i:q)ans=(ans+i.s*fpw(i.v,x)%y)%y;
wr(ans),Pe;

Time complexity: (O()玄学())(大雾

Memory complexity: (O(n))

附上总代码((10.60)s / (9.05)MB)

(打的比珂朵莉树难,空间比珂朵莉树大,跑的比珂朵莉树慢)

//This program is written by Brian Peng.
#pragma GCC optimize("Ofast","inline","no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Rd(a) (a=read())
#define Gc(a) (a=getchar())
#define Pc(a) putchar(a)
int read(){
    int u;char c(getchar());bool k;
    while(!isdigit(c)&&c^'-')if(Gc(c)==EOF)exit(0);
    if(c^'-')k=1,u=c&15;else k=u=0;
    while(isdigit(Gc(c)))u=(u<<1)+(u<<3)+(c&15);
    return k?u:-u;
}
void wr(int a){
    if(a<0)Pc('-'),a=-a;
    if(a<=9)Pc(a|'0');
    else wr(a/10),Pc((a%10)|'0');
}
signed const INF(0x3f3f3f3f),NINF(0xc3c3c3c3);
long long const LINF(0x3f3f3f3f3f3f3f3fLL),LNINF(0xc3c3c3c3c3c3c3c3LL);
#define Ps Pc(' ')
#define Pe Pc('
')
#define Frn0(i,a,b) for(int i(a);i<(b);++i)
#define Frn1(i,a,b) for(int i(a);i<=(b);++i)
#define Frn_(i,a,b) for(int i(a);i>=(b);--i)
#define Mst(a,b) memset(a,b,sizeof(a))
#define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
#define N (262150)
#define Ls (u<<1)
#define Rs (Ls|1)
int n,m,sd,vmx,op,l,r,x,y,ans;
struct SgT{int l,r,v;}t[N];
struct Q{int v,s;};
vector<Q>q;
int rnd(){int r(sd);sd=(sd*7+13)%1000000007;return r;}
void pd(int u){if(t[u].v)t[Ls].v=t[Rs].v=t[u].v,t[u].v=0;}
void bld(int u);
void mdfa(int u);
void mdfs(int u);
void qry(int u);
int fpw(int a,int b){int r(1);a%=y;while(b)b&1?r=r*a%y:0,a=a*a%y,b>>=1;return r;}
signed main(){
    t[1].l=1,t[1].r=Rd(n),Rd(m),Rd(sd),Rd(vmx);
    bld(1);
    while(m--){
        op=rnd()%4+1,l=rnd()%n+1,r=rnd()%n+1;
        if(l>r)swap(l,r);
        x=rnd()%(op==3?r-l+1:vmx)+1;
        switch(op){
            case 1:mdfa(1);break;
            case 2:mdfs(1);break;
            case 3:q.clear(),qry(1);
                sort(q.begin(),q.end(),[](Q a,Q b){return a.v<b.v;});
                for(Q i:q){
                    if(x<=i.s){wr(i.v),Pe;break;}
                    x-=i.s;
                }break;
            case 4:ans=0,y=rnd()%vmx+1,q.clear(),qry(1);
                for(Q i:q)ans=(ans+i.s*fpw(i.v,x)%y)%y;
                wr(ans),Pe;break;
        }
    }
    exit(0);
}
void bld(int u){
    if(t[u].l==t[u].r){t[u].v=rnd()%vmx+1;return;}
    t[Ls].l=t[u].l,t[Rs].l=(t[Ls].r=(t[u].l+t[u].r)>>1)+1,t[Rs].r=t[u].r;
    bld(Ls),bld(Rs);
}
void mdfa(int u){
    if(r<t[u].l||t[u].r<l)return;
    if(l<=t[u].l&&t[u].r<=r&&t[u].v)t[u].v+=x;
    else pd(u),mdfa(Ls),mdfa(Rs);
}
void mdfs(int u){
    if(r<t[u].l||t[u].r<l)return;
    if(l<=t[u].l&&t[u].r<=r)t[u].v=x;
    else pd(u),mdfs(Ls),mdfs(Rs);
}
void qry(int u){
    if(r<t[u].l||t[u].r<l)return;
    if(t[u].v)q.push_back({t[u].v,min(t[u].r,r)-max(t[u].l,l)+1});
    else qry(Ls),qry(Rs);
}

Conclusion:

仔细想想其实这个线段树也是利用随机数据的多次区间设置减少有效懒标记的数量以优化查询复杂度

如果没有区间设置,照样(O(nm))爆炸

所以以后看见线段树是这么构造的,就果断使用珂朵莉树吧(大雾


Special announcement

虽然这题我没打珂朵莉树,但是

我永远喜欢珂朵莉!!!!!

有输入法为证

技术图片

技术图片

以上是关于Solution: 题解 CF896C Willem, Chtholly and Seniorious(线段树解珂朵莉树)的主要内容,如果未能解决你的问题,请参考以下文章

CF896C Willem, Chtholly and Seniorious 珂朵莉树

CF896C Willem, Chtholly and Seniorious

CF896C Willem, Chtholly and Seniorious

Solution: 题解 CF1059E Split the Tree

[CF1228] 简要题解

题解CF1154