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

Intro:

珂朵莉树模板题

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

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

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

来一发定义

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

懒标记\(t_u\):当\(t_u\not=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('\n')
#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

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

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

有输入法为证

原文地址:https://www.cnblogs.com/BrianPeng/p/12356392.html

时间: 2024-10-14 00:44:08

Solution: 题解 CF896C Willem, Chtholly and Seniorious(线段树解珂朵莉树)的相关文章

CF896C Willem, Chtholly and Seniorious 珂朵莉树

问题描述 CF896C LG-CF896C 题解 我expect就是T飞,从这里跳下去,也不碰和珂朵莉相关的任何东西. 珂朵莉树真好使. 珂朵莉树模板. \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace std; #define int long long #define IT set<node>::iterator template <typename Tp> void read(Tp &x){

CF896C Willem, Chtholly and Seniorious

话说,研究珂学的最好方式是-- 其实珂朵莉树很久之前就看过UESTC的那个介绍了,但是由于太菜,听都听不懂. 现在过来学一学,才发现太暴力太优美了!我爱珂朵莉... 这道题要你弄的4个操作是区间加.区间推平.区间排序后的第\(k\)大值和区间任意幂次和. 比较有难度的就是区间任意幂次和.暴力显然行不通的啊!!! 讲道理,珂朵莉树是我看过的唯一支持维护区间任意幂次和的数据结构. 所以用珂朵莉树来搞一搞? 珂朵莉树的单个节点是这样的: struct Nodes { ll l, r; mutable

[SHOI2015]脑洞治疗仪(线段树?珂朵莉树)

题面 这道题超级可爱呢,珂朵莉最可爱了,不,小哀才是最可爱的呢 很好的题,可以考虑用线段树维护,hale表示线段树思路很难,而且难打,不如滚去写珂朵莉树哦 对于操作一:直接将set修改插入即可 对于操作三:最大连续子段和(线段树里面是这样叫的吧)维护即可 对于操作二:我们发现可以考虑先将这段区间里面的1 全部取出来,然后暴力合并区间为0,插入会set里面 之后枚举要修改的区间,从左端点开始搞起,一直后搜索,最后加一个判断,是否已经完全ok即可,具体可参见代码 好了,这道题就解决了 我的代码好像l

cf896C. Willem, Chtholly and Seniorious(ODT)

题意 题目链接 Sol ODT板子题.就是用set维护连续段的大暴力.. 然鹅我抄的板子本题RE提交AC??.. 具体来说,用50 50 658073485 946088556这个数据测试下面的代码,然后在79行停住,看一下bg和i的值会发生神奇的事情.. 问题已解决,确实是那位博主写错了, 只要把split(l)和split(r + 1)反过来就行了 #include<bits/stdc++.h> #define LL long long #define int long long #def

[Codeforces896C] Willem, Chtholly and Seniorious (ODT-珂朵莉树)

无聊学了一下珂朵莉树 珂朵莉树好哇,是可以维护区间x次方和查询的高效数据结构. 思想大致就是一个暴力(相对而言)的树形数据结构 lxl毒瘤太强了,发明了ODT算法(Old Driver Tree老司机算法) 这里有一个大佬ACDreamer的题解 附上链接https://www.luogu.org/blog/ACdreamer/solution-cf896c 还有一个B站的讲解视频 附上链接https://www.bilibili.com/video/av21651173 我不会用珂朵莉树,但是

[ODT]CF 896 C. Willem, Chtholly and Seniorious

题目描述 给出\(n\)个数,支持区间加,区间覆盖,区间第\(k\)小,区间的\(x\)次幂和.数据随机 解题思路 学ODT之前,第四个操作我是维护不来的. 第一次写ODT,ODT在数据随机有区间覆盖操作的情况下有优秀的复杂度. 关键就是用一棵平衡树维护覆盖的区间,其他就是暴力...... #include<cstdio> #include<set> #include<algorithm> #define IT set<jz>::iterator #defi

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

离散化坐标然后线段树解poj2528Mayor&#39;s posters

#include<iostream> #include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> #include<vector> #include<algorithm> using namespace std; bo

【题解】 bzoj1135: [POI2009]Lyz (线段树+霍尔定理)

题面戳我 Solution 二分图是显然的,用二分图匹配显然在这个范围会炸的很惨,我们考虑用霍尔定理. 我们任意选取穿\(l,r\)的号码鞋子的人,那么这些人可以穿的鞋子的范围是\(l,r+d\),这个时候我们可以根据霍尔定理得出满足人人有鞋子穿的时候的式子是 令\(sum[i]\)表示穿\(i\)号鞋子的人数 \[\Sigma^r_{i=l} sum[i] \leq (r-l+1+d)*k\] 我们把这个式子整理下: \[\Sigma^r_{i=l} (sum[i]-k) \leq d*k\]