模板小记4

可持续化线段树

注意$l$和$1$要区分

#include<cstdio> 
#include<algorithm>
#include<cstring>
using namespace std; 
const int N=200010; 
int n,m,b[N<<5],cnt,L[N<<5],R[N<<5],sum[N<<5],a[N<<5],t[N<<5]; 
int update(int pre,int l,int r,int k){
	int p=++cnt;
	L[p]=L[pre]; R[p]=R[pre]; sum[p]=sum[pre]+1; 
	int mid=(l+r)>>1;  
	if (l<r){
		if (k<=mid) L[p]=update(L[pre],l,mid,k); 
		if (k>mid) R[p]=update(R[pre],mid+1,r,k); 
	}
	return p;  
}
int query(int u,int v,int l,int r,int k){
	if (l==r) return l; 
	int mid=(l+r)>>1,s=sum[L[v]]-sum[L[u]]; 
	if (s>=k) return query(L[u],L[v],l,mid,k); else return query(R[u],R[v],mid+1,r,k-s); 
}
int main(){
	scanf("%d%d",&n,&m); 
	for(int i=1;i<=n;i++) scanf("%d",&b[i]),a[i]=b[i]; 
	sort(a+1,a+n+1); 
	int q=unique(a+1,a+n+1)-a-1; 
	for(int i=1;i<=n;i++) {
		int w=lower_bound(a+1,a+1+q,b[i])-a; 
		t[i]=update(t[i-1],1,q,w); 
	}
	for(int i=1;i<=m;i++){
		int k,x,y; 
		scanf("%d%d%d",&x,&y,&k); 
		printf("%d\n",a[query(t[x-1],t[y],1,q,k)]); 
	}
	return 0; 
}

树链剖分

#include<cstdio>
#define rr register 
#define ll long long 
using namespace std; 
const ll N=100011; 
const ll M=400011;
ll n,m,Summ,R,P; 
ll seg[N],rev[M],size[N],son[N],top[N],dep[N]; 
ll num[N],father[N],Max[N],tot; 
ll first[M],next[M],go[M]; 
struct SegmentTree{
    ll l,r,sum,add; 
    #define l(x) tree[x].l 
    #define r(x) tree[x].r 
    #define sum(x) tree[x].sum
    #define add(x) tree[x].add
}tree[M];
inline void myswap(ll &x,ll &y){ll t; t=x; x=y; y=t; return;}
inline void in_add(rr ll x,rr ll y){next[++tot]=first[x],first[x]=tot,go[tot]=y;}
inline void insert(rr ll x,rr ll y){in_add(x,y); in_add(y,x);}
inline ll get(){
    rr char c; 
    while ((c=getchar())<'0'||c>'9'); rr ll res=c-'0'; 
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0'; 
    return res; 
}
inline void write(rr ll x){if (x>9) write(x/10); putchar(x%10+48);}
inline void dfs1(rr ll u,rr ll f){
    rr ll e,v; 
    size[u]=1; 
    father[u]=f; 
    dep[u]=dep[f]+1; 
    for(e=first[u];v=go[e],e;e=next[e])
        if (v!=f){
            dfs1(v,u); 
            size[u]+=size[v]; 
            if (size[v]>size[son[u]]) son[u]=v; 
        }   
    return;                                
}                  
inline void dfs2(ll u,ll linp){
	rr ll e,v;
	seg[u]=++seg[0],rev[seg[0]]=u,top[u]=linp;
	if (!son[u]) return; dfs2(son[u],linp);
	for(e=first[u],v;v=go[e],e;e=next[e])
	if (v!=father[u]&&v!=son[u]) dfs2(v,v);
}
inline void build(ll p,ll l,ll r){
    l(p)=l,r(p)=r; 
    if (l==r) {sum(p)=num[rev[l]]; sum(p)%=P; return;}
    ll mid=l+r>>1; 
    build(p<<1,l,mid); 
    build(p<<1|1,mid+1,r); 
    sum(p)=sum(p<<1)+sum(p<<1|1); 
    sum(p)%=P; 
    return; 
}
inline void spread(ll p){
    if (add(p)){
        sum(p<<1)+=add(p)*(r(p<<1)-l(p<<1)+1)%P; 
        sum(p<<1|1)+=add(p)*(r(p<<1|1)-l(p<<1|1)+1)%P; 
        add(p<<1)+=add(p); 
        add(p<<1|1)+=add(p); 
        add(p)=0; 
        sum(p<<1)%=P; 
        sum(p<<1|1)%=P;
        add(p<<1)%=P; 
        add(p<<1|1)%=P; 
    }
    return; 
}
inline void change(ll p,ll l,ll r,ll d){
    if (l<=l(p)&&r>=r(p)){
        sum(p)+=d*(r(p)-l(p)+1)%P; 
        add(p)+=d; 
        sum(p)%=P;
		add(p)%=P; 
        return; 
    }
    spread(p); 
    ll mid=(l(p)+r(p))>>1; 
    if (l<=mid) change(p<<1,l,r,d);
    if (r>mid) change(p<<1|1,l,r,d); 
    sum(p)=sum(p<<1)+sum(p<<1|1); 
    sum(p)%=P; 
    return; 
}
inline ll query(ll p,ll l,ll r){
    if (l<=l(p)&&r>=r(p)) return sum(p); 
    spread(p); 
    ll mid=(l(p)+r(p))>>1; 
    ll val=0; 
    if (l<=mid) val+=query(p<<1,l,r); 
    val%=P; 
    if (r>mid) val+=query(p<<1|1,l,r); 
    val%=P; 
    return val; 
}

inline void ask(rr ll x,rr ll y){
    rr ll fx=top[x],fy=top[y]; 
    while(fx!=fy){
        if (dep[fx]<dep[fy]) myswap(x,y),myswap(fx,fy); 
        Summ+=query(1,seg[fx],seg[x]); 
        Summ%=P; 
        x=father[fx]; fx=top[x]; 
    }
    if (dep[x]>dep[y]) myswap(x,y); 
    Summ+=query(1,seg[x],seg[y]); 
    Summ%=P; 
    return;
}
inline void change_range(ll x,ll y,ll z){
    z%=P; 
    ll fx=top[x],fy=top[y]; 
    while(fx!=fy){
        if (dep[fx]<dep[fy]) myswap(x,y),myswap(fx,fy); 
        change(1,seg[fx],seg[x],z); 
        x=father[fx]; fx=top[x]; 
    }
    if (dep[x]>dep[y]) myswap(x,y); 
    change(1,seg[x],seg[y],z); 
    return; 
}
inline void change_son(ll x,ll z){
    change(1,seg[x],seg[x]+size[x]-1,z); 
    return;
}
inline void askson(ll x){
    Summ=query(1,seg[x],seg[x]+size[x]-1); 
    return;
}

int main(){ 
    rr ll i,j,k,u,v,s1,s2,sr,z; 
    n=get(); m=get(); R=get(); P=get(); 
    for(i=1;i<=n;i++) num[i]=get(); 
    for(i=1;i<n;i++) s1=get(),s2=get(),insert(s1,s2); 
    dfs1(R,0); dfs2(R,R); 
    build(1,1,seg[0]); 
    for(i=1;i<=m;i++){
        Summ=0; 
        sr=get(); 
        if (sr==1) {
            u=get(),v=get(),z=get(); change_range(u,v,z); 
        } else if (sr==2){
            u=get(),v=get(); ask(u,v); write(Summ%P); putchar('\n'); 
        } else if (sr==3){
            u=get(),v=get(); change_son(u,v); 
        } else {
            u=get(); askson(u); write(Summ%P); putchar('\n'); 
        }
    }
    return 0; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值