zoukankan      html  css  js  c++  java
  • 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

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

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

    有输入法为证

  • 相关阅读:
    exports 与 module.exports 的区别
    [读书笔记] JavaScript设计模式: 单例模式
    mybaits及mybaits generator 插件使用指南(亲测原创)
    【转】系统吞吐量等知识相关
    java的JDBC驱动使用链接数据库
    java程序引用别的jar包打包方法
    ftp服务器不能上传文件故障
    lftp下载文件无法覆盖,提示" file already existst and xfer:clobber is unset" 问题解决
    jar/war文件的解释
    linux 自动输入用户名和密码 ftp
  • 原文地址:https://www.cnblogs.com/BrianPeng/p/12356392.html
Copyright © 2011-2022 走看看