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

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

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

    有输入法为证

  • 相关阅读:
    vue中创建全局单文件组件/命令
    export default与export的区别
    Android Fragment的使用(转载)
    ios 内存管理总结
    object-c 混编 调用C,C++接口
    Python3基础 yield send 获得生成器后,需要先启动一次
    Python3基础 yield next 获取生成器生出的值
    Python3基础 函数 无return、return 空或None 的效果相同
    Python3基础 函数 函数名赋值操作
    Python3基础 函数 函数名作为参数传给函数
  • 原文地址:https://www.cnblogs.com/BrianPeng/p/12356392.html
Copyright © 2011-2022 走看看