【模板整合计划】高阶数据结构—线段树

【模板整合计划】高阶数据结构—线段树

一:【基本操作及扩展】

1.【区间修改(+),区间查询(Sum)】

【模板】线段树 \(1\) \(\text{[P3372]}\)

#include<cstdio>
#define LL long long
#define Re register int
const int N=1e5+3;
int n,x,y,z,T,op,A[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    struct QAQ{LL S,add;}tr[N<<2];
    inline void pushup(Re p){tr[p].S=tr[pl].S+tr[pr].S;}
    inline void updata(Re p,Re L,Re R,LL v){tr[p].S+=v*(R-L+1),tr[p].add+=v;}
    inline void pushdown(Re p,Re L,Re R){
        if(tr[p].add)updata(pl,L,mid,tr[p].add),updata(pr,mid+1,R,tr[p].add),tr[p].add=0;
    }
    inline void build(Re p,Re L,Re R){
        if(L==R){tr[p].S=A[L];return;}
        build(pl,L,mid),build(pr,mid+1,R);
        pushup(p);
    }
    inline void change(Re p,Re L,Re R,Re l,Re r,Re v){
        if(l<=L&&R<=r){updata(p,L,R,v);return;}
        pushdown(p,L,R);
        if(l<=mid)change(pl,L,mid,l,r,v);
        if(r>mid)change(pr,mid+1,R,l,r,v);
        pushup(p);
    }
    inline LL ask(Re p,Re L,Re R,Re l,Re r){
        if(l<=L&&R<=r)return tr[p].S;
        LL ans=0;pushdown(p,L,R);
        if(l<=mid)ans+=ask(pl,L,mid,l,r);
        if(r>mid)ans+=ask(pr,mid+1,R,l,r);
        return ans;
    }
}TR;
int main(){
    in(n),in(T);
    for(Re i=1;i<=n;++i)in(A[i]);
    TR.build(1,1,n);
    while(T--){
        in(op),in(x),in(y);
        if(op<2)in(z),TR.change(1,1,n,x,y,z);
        else printf("%lld\n",TR.ask(1,1,n,x,y));
    }
}

2.【区间修改(+,×),区间查询(Sum)】

【模板】线段树 2 \(\text{[P3373]}\) / 维护序列 \(\text{[P2023]}\) \(\text{[BZOJ1798]}\)**

#include<cstdio>
#define LL long long
#define Re register int
const int N=1e5+3;
int n,x,y,z,T,P,op,A[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    struct QAQ{LL S,mul,add;}tr[N<<2];
    inline void pushup(Re p){tr[p].S=(tr[pl].S+tr[pr].S)%P;}
    inline void updata1(Re p,LL v){
        tr[p].S=(LL)tr[p].S*v%P,tr[p].mul=(LL)tr[p].mul*v%P,tr[p].add=(LL)tr[p].add*v%P;
    }
    inline void updata2(Re p,Re L,Re R,LL v){(tr[p].S+=v*(R-L+1)%P)%=P,(tr[p].add+=v)%=P;}
    inline void pushdown(Re p,Re L,Re R){
        if(tr[p].mul!=1)updata1(pl,tr[p].mul),updata1(pr,tr[p].mul),tr[p].mul=1;
        if(tr[p].add)updata2(pl,L,mid,tr[p].add),updata2(pr,mid+1,R,tr[p].add),tr[p].add=0;
    }
    inline void build(Re p,Re L,Re R){
        tr[p].mul=1;
        if(L==R){tr[p].S=A[L]%P;return;}
        build(pl,L,mid),build(pr,mid+1,R);
        pushup(p);
    }
    inline void change(Re p,Re L,Re R,Re l,Re r,Re v,Re op){
        if(l<=L&&R<=r){if(op<2)updata1(p,v);else updata2(p,L,R,v);return;}
        pushdown(p,L,R);
        if(l<=mid)change(pl,L,mid,l,r,v,op);
        if(r>mid)change(pr,mid+1,R,l,r,v,op);
        pushup(p);
    }
    inline LL ask(Re p,Re L,Re R,Re l,Re r){
        if(l<=L&&R<=r)return tr[p].S;
        LL ans=0;pushdown(p,L,R);
        if(l<=mid)(ans+=ask(pl,L,mid,l,r))%=P;
        if(r>mid)(ans+=ask(pr,mid+1,R,l,r))%=P;
        return ans;
    }
}TR;
int main(){
    in(n),in(T),in(P);
    for(Re i=1;i<=n;++i)in(A[i]);
    TR.build(1,1,n);
    while(T--){
        in(op),in(x),in(y);
        if(op<3)in(z),TR.change(1,1,n,x,y,z,op);
        else printf("%lld\n",TR.ask(1,1,n,x,y));
    }
}

3.【区间修改(+,/),区间查询(Sum,min)】

「雅礼集训 \(2017\) \(\text{Day1}\)」市场 \(\text{[Loj6029]}\)

#include<algorithm>
#include<cstdio>
#include<cmath>
#define LL long long
#define Re register int
#define div(a,b) floor((double)a/b)
using namespace std;
const int N=1e5+3;
int n,x,y,z,T,op,A[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    struct QAQ{LL S,add,min,max;}tr[N<<2];
    inline void pushup(Re p){
        tr[p].S=tr[pl].S+tr[pr].S;
        tr[p].min=min(tr[pl].min,tr[pr].min);
        tr[p].max=max(tr[pl].max,tr[pr].max);
    }
    inline void updata(Re p,Re L,Re R,LL v){tr[p].S+=v*(R-L+1),tr[p].add+=v,tr[p].min+=v,tr[p].max+=v;}
    inline void pushdown(Re p,Re L,Re R){
        if(tr[p].add)updata(pl,L,mid,tr[p].add),updata(pr,mid+1,R,tr[p].add),tr[p].add=0;
    }
    inline void build(Re p,Re L,Re R){
        if(L==R){tr[p].S=tr[p].min=tr[p].max=A[L];return;}
        build(pl,L,mid),build(pr,mid+1,R);
        pushup(p);
    }
    inline void change(Re p,Re L,Re R,Re l,Re r,Re v){
        if(l<=L&&R<=r){updata(p,L,R,v);return;}
        pushdown(p,L,R);
        if(l<=mid)change(pl,L,mid,l,r,v);
        if(r>mid)change(pr,mid+1,R,l,r,v);
        pushup(p);
    }
    inline void change_div(Re p,Re L,Re R,Re l,Re r,Re v){
        if(l<=L&&R<=r&&(div(tr[p].max,v)-tr[p].max==div(tr[p].min,v)-tr[p].min)){
            updata(p,L,R,div(tr[p].max,v)-tr[p].max);return;
        }
        pushdown(p,L,R);
        if(l<=mid)change_div(pl,L,mid,l,r,v);
        if(r>mid)change_div(pr,mid+1,R,l,r,v);
        pushup(p);
    }
    inline LL ask_min(Re p,Re L,Re R,Re l,Re r){
        if(l<=L&&R<=r)return tr[p].min;
        LL ans=1e18;pushdown(p,L,R);
        if(l<=mid)ans=min(ans,ask_min(pl,L,mid,l,r));
        if(r>mid)ans=min(ans,ask_min(pr,mid+1,R,l,r));
        return ans;
    }
    inline LL ask_S(Re p,Re L,Re R,Re l,Re r){
        if(l<=L&&R<=r)return tr[p].S;
        LL ans=0;pushdown(p,L,R);
        if(l<=mid)ans+=ask_S(pl,L,mid,l,r);
        if(r>mid)ans+=ask_S(pr,mid+1,R,l,r);
        return ans;
    }
}TR;
int main(){
    in(n),in(T);
    for(Re i=1;i<=n;++i)in(A[i]);
    TR.build(1,1,n);
    while(T--){
        in(op),in(x),in(y),++x,++y;
        if(op<2)in(z),TR.change(1,1,n,x,y,z);
        else if(op<3)in(z),TR.change_div(1,1,n,x,y,z);
        else if(op<4)printf("%lld\n",TR.ask_min(1,1,n,x,y));
        else printf("%lld\n",TR.ask_S(1,1,n,x,y));
    }
}

4.【区间修改(sqrt),区间查询(Sum)】

上帝造题的七分钟 \(2\) / 花神游历各国 \(\text{[P4145]}\) \(\text{[Loj10128] [Bzoj3211]}\)

\(\text{GSS4 - Can you answer these queries IV} [SP2713]\)

一个数不断地求 \(sqrt\) 会迅速变为 \(1\),此时不需要再继续开方,暴力单修加上剪枝即可。

#include<algorithm>
#include<cstdio>
#include<cmath>
#define LL long long
#define Re register int
using namespace std;
const int N=1e5+3;
int n,x,y,z,T,op;LL A[N];
template<typename T>inline void in(T &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    struct QAQ{LL S,max;}tr[N<<2];
    inline void pushup(Re p){
        tr[p].S=tr[pl].S+tr[pr].S;
        tr[p].max=max(tr[pl].max,tr[pr].max);
    }
    inline void build(Re p,Re L,Re R){
        if(L==R){tr[p].S=tr[p].max=A[L];return;}
        build(pl,L,mid),build(pr,mid+1,R);
        pushup(p);
    }
    inline void change(Re p,Re L,Re R,Re l,Re r){
        if(tr[p].max<=1)return;
        if(L==R){tr[p].max=tr[p].S=sqrt(tr[p].S);return;}
        if(l<=mid)change(pl,L,mid,l,r);
        if(r>mid)change(pr,mid+1,R,l,r);
        pushup(p);
    }
    inline LL ask(Re p,Re L,Re R,Re l,Re r){
        if(l<=L&&R<=r)return tr[p].S;
        LL ans=0;
        if(l<=mid)ans+=ask(pl,L,mid,l,r);
        if(r>mid)ans+=ask(pr,mid+1,R,l,r);
        return ans;
    }
}TR;
int main(){
    in(n);
    for(Re i=1;i<=n;++i)in(A[i]);
    TR.build(1,1,n),in(T);
    while(T--){
        in(op),in(x),in(y);if(x>y)swap(x,y);
        if(op)printf("%lld\n",TR.ask(1,1,n,x,y));
        else TR.change(1,1,n,x,y);
    }
}

5.【单点修改(+),区间查询(最大子段和)】

\(\text{GSS3 - Can you answer these queries III} [SP1716]\)

对每个区间维护最大子序列 \(S\),紧靠左边界的最大子序列 \(ls\),紧靠右边界的最大子序列 \(rs\)

#include<algorithm>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=5e4+3;
int n,x,y,T,op,A[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    struct QAQ{LL S,max,lmax,rmax;}tr[N<<2];
    inline void pushup(QAQ &A,const QAQ &L,const QAQ &R){
        A.S=L.S+R.S;
        A.lmax=max(L.lmax,L.S+R.lmax);
        A.rmax=max(R.rmax,R.S+L.rmax);
        A.max=max(max(max(L.max,R.max),max(A.lmax,A.rmax)),L.rmax+R.lmax);
    }
    inline void change(Re p,Re L,Re R,Re x,Re v){
        if(L==R){tr[p].S=tr[p].max=tr[p].lmax=tr[p].rmax=v;return;}
        if(x<=mid)change(pl,L,mid,x,v);
        else change(pr,mid+1,R,x,v);
        pushup(tr[p],tr[pl],tr[pr]);
    }
    inline QAQ ask(Re p,Re L,Re R,Re l,Re r){
        if(l<=L&&R<=r)return tr[p];
        if(r<=mid)return ask(pl,L,mid,l,r);
        else if(l>mid)return ask(pr,mid+1,R,l,r);
        else{QAQ ans;pushup(ans,ask(pl,L,mid,l,r),ask(pr,mid+1,R,l,r));return ans;}
    }
}TR;
int main(){
    in(n);
    for(Re i=1;i<=n;++i)in(A[i]),TR.change(1,1,n,i,A[i]);
    in(T);
    while(T--){
        in(op),in(x),in(y);
        if(op)printf("%lld\n",TR.ask(1,1,n,x,y).max);
        else TR.change(1,1,n,x,y);
    }
}

6.【区间修改(+),区间查询(GCD)】

\(\text{Interval}\) \(\text{GCD}\) \(\text{[CH4302]}\)

\(gcd(x,y)=gcd(x,y-x)\)
\(gcd(x,y,z)=gcd(x,y-x,z-y)\)
\(...\)

线段树维护差分序列 \(c\),树状数组维护原序列 \(a\)\(gcd(a[l],a[l+1]...a[r])=gcd(a[l],gcd(c[l+1]...c[r]))\)

#include<cstdio>
#define LL long long
#define Re register int
const int N=5e5+3;
int n,x,y,T;LL z,A[N];char op;
template<typename T>inline void in(T &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline LL abs(LL a){return a<0?-a:a;}
inline LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
struct BIT{
    LL C[N];
    inline void add(Re x,LL v){while(x<=n)C[x]+=v,x+=x&-x;}
    inline void add(Re L,Re R,LL v){add(L,v),add(R+1,-v);}
    inline LL ask(Re x){LL ans=0;while(x)ans+=C[x],x-=x&-x;return ans;}
}TR0;
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    LL tr[N<<2];
    inline void pushup(Re p){tr[p]=gcd(tr[pl],tr[pr]);}
    inline void build(Re p,Re L,Re R){
        if(L==R){tr[p]=A[L]-A[L-1];return;}
        build(pl,L,mid),build(pr,mid+1,R);
        pushup(p);
    }
    inline void change(Re p,Re L,Re R,Re x,LL v){
        if(L==R){tr[p]+=v;return;}
        if(x<=mid)change(pl,L,mid,x,v);
        else change(pr,mid+1,R,x,v);
        pushup(p);
    }
    inline LL ask(Re p,Re L,Re R,Re l,Re r){
        if(l<=L&&R<=r)return abs(tr[p]);
        if(r<=mid)return ask(pl,L,mid,l,r);
        else if(l>mid)return ask(pr,mid+1,R,l,r);
        else return gcd(ask(pl,L,mid,l,r),ask(pr,mid+1,R,l,r));
    }
}TR;
int main(){
    in(n),in(T);
    for(Re i=1;i<=n;++i)in(A[i]),TR0.add(i,i,A[i]);
    TR.build(1,1,n);
    while(T--){
        scanf(" %c",&op),in(x),in(y);
        if(op=='Q')printf("%lld\n",gcd(TR0.ask(x),TR.ask(1,1,n,x+1,y)));
        else{
            in(z),TR0.add(x,y,z),TR.change(1,1,n,x,z);if(y<n)TR.change(1,1,n,y+1,-z);
        }
    }
}

二:【扫描线】

1.【面积】

【模板】 扫描线 \(\text{[P5490]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define y1 yyyy
#define LL long long
#define Re register int
using namespace std;
const int N=1e5+3;
int n,m,T,x1,y1,x2,y2,b[N<<1];LL ans;
struct Line{int x,y1,y2,k;inline bool operator<(const Line &O)const{return x<O.x;}}A[N<<1];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    struct QAQ{int cnt,len;}tr[N<<3];//因为离散化,这里要开8倍
    inline void pushup(Re p,Re L,Re R){
        if(tr[p].cnt)tr[p].len=b[R+1]-b[L];//注意这里是b[R+1]-b[L]
        else tr[p].len=(L==R)?0:tr[pl].len+tr[pr].len;
    }
    inline void change(Re p,Re L,Re R,Re l,Re r,Re v){
        if(l<=L&&R<=r){tr[p].cnt+=v,pushup(p,L,R);return;}
        if(l<=mid)change(pl,L,mid,l,r,v);
        if(r>mid)change(pr,mid+1,R,l,r,v);
        pushup(p,L,R);
    }
}TR;
int main(){
    in(T);
    while(T--){
        in(x1),in(y1),in(x2),in(y2);
        A[++n]=(Line){x1,y1,y2,1},A[++n]=(Line){x2,y1,y2,-1};
        b[++m]=y1,b[++m]=y2;
    }
    sort(A+1,A+n+1),sort(b+1,b+m+1),m=unique(b+1,b+m+1)-b-1;
    for(Re i=1;i<n;++i){
        Re y1=lower_bound(b+1,b+m+1,A[i].y1)-b,y2=lower_bound(b+1,b+m+1,A[i].y2)-b;
        TR.change(1,1,m-1,y1,y2-1,A[i].k);
        ans+=(LL)TR.tr[1].len*(A[i+1].x-A[i].x);
    }
    printf("%lld\n",ans);
}

2.【周长】

【模板】 矩形周长 \(\text{Picture [P1856]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define y1 yyyy
#define LL long long
#define Re register int
using namespace std;
const int N=5e4+3,M=2e4+3;
int n,m,ans,Max=10000,x1[N],y1[N],x2[N],y2[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    struct QAQ{int S,cnt;}tr[M<<2];
    inline void pushup(Re p,Re L,Re R){
        if(tr[p].cnt)tr[p].S=R-L+1;
        else tr[p].S=(L==R)?0:tr[pl].S+tr[pr].S;
    }
    inline void change(Re p,Re L,Re R,Re l,Re r,Re v){
        if(l<=L&&R<=r){tr[p].cnt+=v,pushup(p,L,R);return;}
        if(l<=mid)change(pl,L,mid,l,r,v);
        if(r>mid)change(pr,mid+1,R,l,r,v);
        pushup(p,L,R);
    }
}TR1,TR2;
struct Line{
    int x,y1,y2,k;Line(Re X=0,Re Y1=0,Re Y2=0,Re K=0){x=X,y1=Y1,y2=Y2,k=K;}
    inline bool operator<(const Line &O)const{return x!=O.x?x<O.x:k>O.k;}//x相等时必须把添加操作放在前面
}L1[N<<1],L2[N<<1];
int main(){
//    freopen("123.txt","r",stdin);
    in(n);
    for(Re i=1;i<=n;++i)
        in(x1[i]),in(y1[i]),in(x2[i]),in(y2[i]),x1[i]+=Max,y1[i]+=Max,x2[i]+=Max,y2[i]+=Max,
        L1[++m]=Line(x1[i],y1[i],y2[i],1),L2[m]=Line(y1[i],x1[i],x2[i],1),
        L1[++m]=Line(x2[i],y1[i],y2[i],-1),L2[m]=Line(y2[i],x1[i],x2[i],-1);
    sort(L1+1,L1+m+1),sort(L2+1,L2+m+1);
    for(Re i=1,j=0;i<=m;i=j+1){
        Re last=TR1.tr[1].S;
        ++j,TR1.change(1,1,Max<<1,L1[j].y1+1,L1[j].y2,L1[j].k);
        while(j+1<=m&&L1[j].x==L1[j+1].x&&L1[j].k==L1[j+1].k)++j,TR1.change(1,1,Max<<1,L1[j].y1+1,L1[j].y2,L1[j].k);
        ans+=abs(last-TR1.tr[1].S);
    }
    for(Re i=1,j=0;i<=m;i=j+1){
        Re last=TR2.tr[1].S;
        ++j,TR2.change(1,1,Max<<1,L2[j].y1+1,L2[j].y2,L2[j].k);
        while(j+1<=m&&L2[j].x==L2[j+1].x&&L2[j].k==L2[j+1].k)++j,TR2.change(1,1,Max<<1,L2[j].y1+1,L2[j].y2,L2[j].k);
        ans+=abs(last-TR2.tr[1].S);
    }
    printf("%d\n",ans);
}

三:【权值线段树区间第 K 小】

#define Re register int
#define pl tree[p].PL
#define pr tree[p].PR
inline int ask(Re p,Re L,Re R,Re k){//查询第k小
    if(L==R)return L;//边界叶节点
    Re tmp=tree[pl].g;//计算左子树(数值范围在L~mid的数)共有多少个数字
    if(tmp>=k)return ask(pl,L,mid,k);
//左子树已经超过k个,说明第k小在左子树里面
    else return ask(pr,mid+1,R,k-tmp);
//左子树不足k个数字,应该在右子树中找到第(k-tmp)小
}

四:【线段树的合并与分裂】

1.【线段树合并】

【模板】 晋升者计数 \(\text{Promotion Counting P [P3605]}\)

#include<algorithm>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=1e5+3,logN=17;
int n,m,x,o,T,op,b[N],A[N],Ans[N],head[N];
struct QAQ{int to,next;}a[N];
inline void add(Re x,Re y){a[++o].to=y,a[o].next=head[x],head[x]=o;}
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
int pt[N];
struct Segment_Tree{
    #define pl (tr[p].lp)
    #define pr (tr[p].rp)
    #define mid ((L+R)>>1)
    int O;
    struct QAQ{int lp,rp,S;}tr[N*(logN+1)];//注意一次单点修改的使用空间是\ceil(log_2^N)+1
    inline void pushup(Re p){tr[p].S=tr[pl].S+tr[pr].S;}
    inline void change(Re &p,Re L,Re R,Re x){
        p=++O,++tr[p].S;
        if(L==R)return;
        if(x<=mid)change(pl,L,mid,x);
        else change(pr,mid+1,R,x);
    }
    inline int merge(Re p,Re q,Re L,Re R){
        if(!p||!q)return p+q;
        if(L==R){tr[p].S+=tr[q].S;return p;}
        pl=merge(pl,tr[q].lp,L,mid);
        pr=merge(pr,tr[q].rp,mid+1,R);
        pushup(p);return p;
    }
    inline int ask(Re &p,Re L,Re R,Re l,Re r){
        if(!p)return 0;
        if(l<=L&&R<=r)return tr[p].S;
        Re ans=0;
        if(l<=mid)ans+=ask(pl,L,mid,l,r);
        if(r>mid)ans+=ask(pr,mid+1,R,l,r);
        return ans;
    }
}TR;
inline void dfs(Re x,Re fa){
    TR.change(pt[x],1,m,A[x]);
    for(Re i=head[x],to;i;i=a[i].next)
        dfs(to=a[i].to,x),pt[x]=TR.merge(pt[x],pt[to],1,m);
    if(A[x]<m)Ans[x]=TR.ask(pt[x],1,m,A[x]+1,m);
}
int main(){
    in(n);
    for(Re i=1;i<=n;++i)in(A[i]),b[i]=A[i];
    sort(b+1,b+n+1),m=unique(b+1,b+n+1)-b-1;
    for(Re i=1;i<=n;++i)A[i]=lower_bound(b+1,b+m+1,A[i])-b;
    for(Re i=2;i<=n;++i)in(x),add(x,i);
    dfs(1,0);
    for(Re i=1;i<=n;++i)printf("%d\n",Ans[i]);
}

2.【线段树合并维护 DP 转移 / 整体 DP】

【模板】 \(\text{Treeland Tour}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=6003;
int n,m,x,y,t,o,Ans,b[N],A[N],pt[N],head[N];
struct QAQ{int to,next;}a[N<<1];
inline void add(Re x,Re y){a[++o].to=y,a[o].next=head[x],head[x]=o;}
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Segment_Tree{
    #define pl (tr[p].lp)
    #define pr (tr[p].rp)
    #define mid ((L+R)>>1)
    int O;
    struct QAQ{int lp,rp,up,down;}tr[N*13*2];
    inline void pushup(Re p){
        tr[p].up=max(tr[pl].up,tr[pr].up);
        tr[p].down=max(tr[pl].down,tr[pr].down);
    }
    inline void change1(Re &p,Re L,Re R,Re x,Re v){
        if(!p)p=++O;
        if(L==R){tr[p].up=max(tr[p].up,v);return;}
        if(x<=mid)change1(pl,L,mid,x,v);
        else change1(pr,mid+1,R,x,v);
        pushup(p);
    }
    inline void change2(Re &p,Re L,Re R,Re x,Re v){
        if(!p)p=++O;
        if(L==R){tr[p].down=max(tr[p].down,v);return;}
        if(x<=mid)change2(pl,L,mid,x,v);
        else change2(pr,mid+1,R,x,v);
        pushup(p);
    }
    inline int ask1(Re p,Re L,Re R,Re l,Re r){
        if(!p)return 0;
        if(l<=L&&R<=r)return tr[p].up;
        Re ans=0;
        if(l<=mid)ans=max(ans,ask1(pl,L,mid,l,r));
        if(r>mid)ans=max(ans,ask1(pr,mid+1,R,l,r));
        return ans;
    }
    inline int ask2(Re p,Re L,Re R,Re l,Re r){
        if(!p)return 0;
        if(l<=L&&R<=r)return tr[p].down;
        Re ans=0;
        if(l<=mid)ans=max(ans,ask2(pl,L,mid,l,r));
        if(r>mid)ans=max(ans,ask2(pr,mid+1,R,l,r));
        return ans;
    }
    inline int merge(Re p,Re q,Re L,Re R){
        if(!p||!q)return p+q;
        if(L==R){tr[p].up=max(tr[p].up,tr[q].up),tr[p].down=max(tr[p].down,tr[q].down);return p;}
        Ans=max(Ans,max(tr[pl].up+tr[tr[q].rp].down,tr[pr].down+tr[tr[q].lp].up));
        pl=merge(pl,tr[q].lp,L,mid);
        pr=merge(pr,tr[q].rp,mid+1,R);
        pushup(p);return p;
    }
}TR;
inline void dfs(Re x,Re fa){
    Re up=0,down=0;
    for(Re i=head[x],to;i;i=a[i].next)
        if((to=a[i].to)!=fa){
            dfs(to,x);
            Re tmp1=TR.ask1(pt[to],1,t,1,A[x]-1),tmp2=TR.ask2(pt[to],1,t,A[x]+1,t);
            Ans=max(Ans,max(up+tmp2+1,down+tmp1+1));
            up=max(up,tmp1),down=max(down,tmp2);
            pt[x]=TR.merge(pt[x],pt[a[i].to],1,t);
        }
    TR.change1(pt[x],1,t,A[x],up+1),TR.change2(pt[x],1,t,A[x],down+1);
}
int main(){
//    freopen("123.txt","r",stdin);
    in(n),m=n-1;
    for(Re i=1;i<=n;++i)in(A[i]),b[i]=A[i];
    sort(b+1,b+n+1),t=unique(b+1,b+n+1)-b;
    for(Re i=1;i<=n;++i)A[i]=lower_bound(b+1,b+t+1,A[i])-b;
    while(m--)in(x),in(y),add(x,y),add(y,x);
    dfs(1,0),printf("%d\n",Ans);
}

3.【线段树分裂】

(1).【分裂指定区间】

【模板】 线段树分裂 \(\text{[P5494]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=2e5+3;
int n,m,x,y,p,T,op,A[N],pt[N];LL K;
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Segment_Tree{
    #define pl tr[p].lp
    #define pr tr[p].rp
    #define mid ((L+R)>>1)
    int O;
    struct QAQ{int lp,rp;LL S;}tr[N*20];
    inline void pushup(Re p){tr[p].S=tr[pl].S+tr[pr].S;}
    inline void build(Re &p,Re L,Re R){
        p=++O;
        if(L==R){tr[p].S=A[L];return;}
        build(pl,L,mid),build(pr,mid+1,R);
        pushup(p);
    }
    inline void change(Re &p,Re L,Re R,Re x,Re v){
        if(!p)p=++O;
        if(L==R){tr[p].S+=v;return;}
        if(x<=mid)change(pl,L,mid,x,v);
        else change(pr,mid+1,R,x,v);
        pushup(p);
    }
    inline LL ask(Re p,Re L,Re R,Re l,Re r){
        if(!p)return 0;
        if(l<=L&&R<=r)return tr[p].S;
        LL ans=0;
        if(l<=mid)ans+=ask(pl,L,mid,l,r);
        if(r>mid)ans+=ask(pr,mid+1,R,l,r);
        return ans;
    }
    inline int ask(Re p,Re L,Re R,LL k){
        if(!p||k>tr[p].S)return -1;
        if(L==R)return L;
        LL tmp=tr[pl].S;
        if(tmp>=k)return ask(pl,L,mid,k);
        else return ask(pr,mid+1,R,k-tmp);
    }
    inline int merge(Re p,Re q,Re L,Re R){//在本题中q不会再次出现,所以可以随意糟蹋而不用新建节点
        if(!p||!q)return p+q;
        if(L==R){tr[p].S+=tr[q].S;return p;}
        pl=merge(pl,tr[q].lp,L,mid);
        pr=merge(pr,tr[q].rp,mid+1,R);
        pushup(p);return p;
    }
    inline void split(Re &p,Re &q,Re L,Re R,Re l,Re r){//把tr[q]中的[l,r]剪切到tr[p]中
        if(!q)return;
        if(l<=L&&R<=r){p=q,q=0;return;}
        p=++O;
        if(l<=mid)split(pl,tr[q].lp,L,mid,l,r);
        if(r>mid)split(pr,tr[q].rp,mid+1,R,l,r);
        pushup(p),pushup(q);
    }
}T1;
int main(){
//    freopen("123.txt","r",stdin);
    in(m),in(T);
    for(Re i=1;i<=m;++i)in(A[i]);
    T1.build(pt[n=1],1,m);
    while(T--){
        in(op),in(p);
        if(op<1)in(x),in(y),T1.split(pt[++n],pt[p],1,m,x,y);
        else if(op<2)in(x),pt[p]=T1.merge(pt[p],pt[x],1,m),pt[x]=0;
        else if(op<3)in(x),in(y),T1.change(pt[p],1,m,y,x);
        else if(op<4)in(x),in(y),printf("%lld\n",T1.ask(pt[p],1,m,x,y));
        else scanf("%lld",&K),printf("%d\n",T1.ask(pt[p],1,m,K));
    }
}

(2).【分裂区间前/后 K 个】

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#define LL long long
#define Re register int
#define IT set<QAQ>::iterator
using namespace std;
const int N=1e5+3;
int n,m,l,r,T,op,A[N],tmp[N],cnt[N],Ans[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct QAQ{
    int l,r;mutable int pt,op; 
    QAQ(Re L=0,Re R=0,Re OP=0,Re PT=0){l=L,r=R,op=OP,pt=PT;};
    inline bool operator<(const QAQ &O)const{return l<O.l;}
};
set<QAQ>s;
struct Segment_Tree{
    #define pl tr[p].lp
    #define pr tr[p].rp
    #define mid ((L+R)>>1)
    int O;
    struct QAQ{int S,lp,rp;}tr[N*60];
    inline void pushup(Re p){tr[p].S=tr[pl].S+tr[pr].S;}
    inline void change(Re &p,Re L,Re R,Re x){
        p=++O;
        if(L==R){tr[p].S=1;return;}
        if(x<=mid)change(pl,L,mid,x);
        else change(pr,mid+1,R,x);
        pushup(p);
    }
    inline int merge(Re p,Re q,Re L,Re R){
        if(!p||!q)return p+q;
        if(L==R){tr[p].S+=tr[q].S;return p;}
        pl=merge(pl,tr[q].lp,L,mid);
        pr=merge(pr,tr[q].rp,mid+1,R);
        pushup(p);return p;
    }
    inline void split1(Re &p,Re q,Re L,Re R,Re k){//保留q中的前k个,其他的剪切给p
        tr[p=++O].S=tr[q].S-k,tr[q].S=k;
        if(L==R)return;
        Re tmp=tr[tr[q].lp].S;
        if(k>tmp)split1(pr,tr[q].rp,mid+1,R,k-tmp);//q的左儿子全部保留,分裂右儿子
        else pr=tr[q].rp,tr[q].rp=0;//右儿子全部剪切
        if(k<tmp)split1(pl,tr[q].lp,L,mid,k);//q的右儿子全部保留,分裂左儿子
    }
    inline void split2(Re &p,Re q,Re L,Re R,Re k){//保留q中的后k个,其他的剪切给p
        tr[p=++O].S=tr[q].S-k,tr[q].S=k;
        if(L==R)return;
        Re tmp=tr[tr[q].rp].S;
        if(k>tmp)split2(pl,tr[q].lp,L,mid,k-tmp);//q的右儿子全部保留,分裂左儿子
        else pl=tr[q].lp,tr[q].lp=0;//左儿子全部剪切
        if(k<tmp)split2(pr,tr[q].rp,mid+1,R,k);//q的左儿子全部保留,分裂右儿子
    }
    inline void dfs(Re p,Re L,Re R){
        if(!p)return;
        if(L==R){cnt[tmp[++tmp[0]]=L]=tr[p].S;return;}
        dfs(pl,L,mid),dfs(pr,mid+1,R);
    }
}T1;
inline IT split(Re w){
    IT it=s.lower_bound(QAQ(w));
    if(it!=s.end()&&it->l==w)return it;
    --it;
    Re L=it->l,R=it->r,op=it->op,pt=it->pt,ptt=0;
    s.erase(it);
    if(op)T1.split1(ptt,pt,1,m,w-1-L+1);//保留pt的前K个,其余丢入ptt
    else T1.split2(ptt,pt,1,m,w-1-L+1);//保留pt的后K个,其余丢入ptt
    s.insert(QAQ(L,w-1,op,pt));
    return s.insert(QAQ(w,R,op,ptt)).first;
}
inline void assign(Re l,Re r,Re op){//op=1:升序 op=0:降序
    if(l==r)return;
    IT itr=split(r+1),itl=split(l),it=itl;
    Re pt=0;
    while(it!=itr)pt=T1.merge(pt,it->pt,1,m),it->pt=0,++it;
    s.erase(itl,itr),s.insert(QAQ(l,r,op,pt));
}
int main(){
//    freopen("123.txt","r",stdin);
    in(n),in(T),m=n;
    for(Re i=1;i<=n;++i)in(A[i]);
    s.insert(QAQ(n+1,n+1));
    for(Re i=1;i<=n;++i){
        QAQ tmp(i,i,0,0);T1.change(tmp.pt,1,m,A[i]),s.insert(tmp);
    }
    while(T--)in(op),in(l),in(r),op^=1,assign(l,r,op);
    IT itl=s.lower_bound(QAQ(1)),itr=s.lower_bound(QAQ(n+1));
    while(itl!=itr){
        tmp[0]=0,T1.dfs(itl->pt,1,m);
        if(itl->op)for(Re i=1;i<=tmp[0];++i)
            for(Re j=1;j<=cnt[tmp[i]];++j)
                Ans[++Ans[0]]=tmp[i];
        else for(Re i=tmp[0];i>=1;--i)
            for(Re j=1;j<=cnt[tmp[i]];++j)
                Ans[++Ans[0]]=tmp[i];
        ++itl;
    }
    in(op),printf("%d\n",Ans[op]);
}

排序 \(\text{[HEOI2016/TJOI2016] [P2824]}\)

五:【可持续化线段树—静态主席树】

【模板】可持久化线段树 \(1\) (主席树) \(\text{[3834]}\) / \(\text{K-th Number [POJ2104]}\) \(\text{[SP3946]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=2e5+3,logN=18;
int n,m,x,y,z,T,b[N],A[N],pt[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct President_Tree{
    #define pl tr[p].lp
    #define pr tr[p].rp
    #define mid (L+R>>1)
    int O;
    struct QAQ{int S,lp,rp;}tr[N*(logN+1)];
    inline void creat(Re &p,Re q,Re L,Re R,Re w){
        p=++O,tr[p]=tr[q],++tr[p].S;
        if(L==R)return;
        if(w<=mid)creat(pl,tr[q].lp,L,mid,w);
        else creat(pr,tr[q].rp,mid+1,R,w);
    }
    inline int ask(Re p,Re q,Re L,Re R,Re k){
        if(L==R)return L;
        Re tmp=tr[pl].S-tr[tr[q].lp].S;
        if(tmp>=k)return ask(pl,tr[q].lp,L,mid,k);
        else return ask(pr,tr[q].rp,mid+1,R,k-tmp);
    }
}T1;
int main(){
//    freopen("123.txt","r",stdin);
    in(n),in(T);
    for(Re i=1;i<=n;++i)in(A[i]),b[i]=A[i];
    sort(b+1,b+n+1),m=unique(b+1,b+n+1)-b-1;
    for(Re i=1;i<=n;++i)T1.creat(pt[i],pt[i-1],1,m,lower_bound(b+1,b+m+1,A[i])-b);
    while(T--)in(x),in(y),in(z),printf("%d\n",b[T1.ask(pt[y],pt[x-1],1,m,z)]);
}

六:【树套树】

1.【单修(权值),区查(第 K 小)】

【模板】 \(\text{Dynamic Rankings [P2617]}\) \(\text{[ZOJ2112]}\) \(\text{[BZOJ1901]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=1e5+3;
int n,m,T,b[N<<1],A[N];char op[N];
struct QWQ{int x,y,k;}Q[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
int t1,t2,pt[N],ptl[20],ptr[20];
struct President_Tree{
    #define pl (tr[p].lp)
    #define pr (tr[p].rp)
    #define mid ((L+R)>>1)
    int O;
    struct QAQ{int S,lp,rp;}tr[(N<<1)*200];
    inline void change(Re &p,Re L,Re R,Re x,Re v){
        if(!p)p=++O;tr[p].S+=v;
        if(L==R)return;
        if(x<=mid)change(pl,L,mid,x,v);
        else change(pr,mid+1,R,x,v);
    }
    inline int ask(Re p,Re L,Re R,Re K){
        if(L==R)return L;
        Re tmp=0;
        for(Re i=1;i<=t1;++i)tmp-=tr[tr[ptl[i]].lp].S;
        for(Re i=1;i<=t2;++i)tmp+=tr[tr[ptr[i]].lp].S;
        if(K<=tmp){
            for(Re i=1;i<=t1;++i)ptl[i]=tr[ptl[i]].lp;
            for(Re i=1;i<=t2;++i)ptr[i]=tr[ptr[i]].lp;
            return ask(pl,L,mid,K);
        }
        else{
            for(Re i=1;i<=t1;++i)ptl[i]=tr[ptl[i]].rp;
            for(Re i=1;i<=t2;++i)ptr[i]=tr[ptr[i]].rp;
            return ask(pr,mid+1,R,K-tmp);
        }
    }
}SG;
struct BIT{
    inline void add(Re x,Re v){
        for(Re i=x;i<=n;i+=i&-i)SG.change(pt[i],1,m,A[x],v);
    }
    inline int ask(Re L,Re R,Re k){
        t1=t2=0;
        for(Re i=L-1;i;i-=i&-i)ptl[++t1]=pt[i];
        for(Re i=R;i;i-=i&-i)ptr[++t2]=pt[i];
        return SG.ask(1,1,m,k);
    }
}TR;
int main(){
    in(n),in(T),m=n;
    for(Re i=1;i<=n;++i)in(A[i]),b[i]=A[i];
    for(Re i=1;i<=T;++i){
        scanf(" %c",&op[i]),in(Q[i].x),in(Q[i].y);
        if(op[i]=='Q')in(Q[i].k);
        else b[++m]=Q[i].y;
    }
    sort(b+1,b+m+1),m=unique(b+1,b+m+1)-b-1;
    for(Re i=1;i<=n;++i)A[i]=lower_bound(b+1,b+m+1,A[i])-b;
    for(Re i=1;i<=T;++i)if(op[i]=='C')Q[i].y=lower_bound(b+1,b+m+1,Q[i].y)-b;
    for(Re i=1;i<=n;++i)TR.add(i,1);
    for(Re i=1;i<=T;++i){
        if(op[i]=='Q')printf("%d\n",b[TR.ask(Q[i].x,Q[i].y,Q[i].k)]);
        else TR.add(Q[i].x,-1),A[Q[i].x]=Q[i].y,TR.add(Q[i].x,1);
    }
}

2.【单修(权值),区查(排名、第 K 小、前驱、后继)】

【模板】二逼平衡树(树套树)\([P3380]\) \([BZOJ3196]\) \([TYVJ1730]\)

好长的标题啊QAQ。

众所周知,万能的线段树啥都能维护

#include<algorithm>
#include<cstring>
#include<cstdio>
#define mid (L+R>>1)
#define Re register int
#define pl tree[p].lp
#define pr tree[p].rp
#define F(i,a,b) for(Re i=a;i<=b;++i)
#define lo(o) lower_bound(b+1,b+m+1,o)-b
using namespace std;
const int N=1e5+3,inf=2147483647;//【N不乘2 WA上天】由于要离散化,加上查询最多n+m(即2*n)个数据
int x,y,z,n,m,T,t,fu,cnt,tl,tr,a[N],b[N],pt[N],C[N],opt[N],ptl[20],ptr[20];
struct QAQ{int g,lp,rp;}tree[N*250];//本应是17*17=289左右,开小一点也无所谓,因为根本用不到
struct O_O{int l,r,k;}Q[N];//储存Q次查询的具体内容,方便离散化
struct T_T{int i,x;}c[N];//单点修改的具体内容
inline void in(Re &x){
    x=fu=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
inline int ask_kth(Re L,Re R,Re k){//查询第k小
    if(L==R)return b[R];//【映射混用 WA上天】注意:返回的值需要用到的是哪一个映射数组不能搞错
    Re tmp=0;
    F(i,1,tl)tmp-=tree[tree[ptl[i]].lp].g;//计算左子树信息
    F(i,1,tr)tmp+=tree[tree[ptr[i]].lp].g;//计算左子树信息
    if(tmp>=k){
        F(i,1,tl)ptl[i]=tree[ptl[i]].lp;//更新ptl,ptr所指向的节点编号
        F(i,1,tr)ptr[i]=tree[ptr[i]].lp;
        return ask_kth(L,mid,k);
    }
    else{
        F(i,1,tl)ptl[i]=tree[ptl[i]].rp;
        F(i,1,tr)ptr[i]=tree[ptr[i]].rp;
        return ask_kth(mid+1,R,k-tmp);
    }
}
inline int ask_kth_pre(Re L,Re R,Re k){//查询第k小(中转站)
    tl=tr=0;//(注意L-1)
    for(Re i=L-1;i;i-=i&-i)ptl[++tl]=pt[i];//先把所有要更新的位置的线段树根节点记录下来
    for(Re i=R;i;i-=i&-i)ptr[++tr]=pt[i];//方便后面递归更新信息
    return ask_kth(1,m,k);
}
inline void add(Re &p,Re L,Re R,Re w,Re v){//【单点修改】
    if(!p)p=++cnt;tree[p].g+=v;
    if(L==R)return;
    if(w<=mid)add(pl,L,mid,w,v);
    else add(pr,mid+1,R,w,v);
}
inline void add_pre(Re x,Re v){//【单点修改】
    Re w=lo(a[x]);//【映射混用 TLE上天】注意函数传进来的参数x是在原数列的位置c[i].i(方便更新原数列),这里各种映射数组的调用不要搞错
    for(Re i=x;i<=n;i+=i&-i)add(pt[i],1,m,w,v);//树状数组思想更新信息
}
inline int ask_level(Re p,Re L,Re R,Re x){//查询小于等于x的数的个数
    if(L==R)return tree[p].g;
    if(x<=mid)return ask_level(pl,L,mid,x);
    else return tree[pl].g+ask_level(pr,mid+1,R,x);
}
inline int ask_level_pre(Re L,Re R,Re w){//查询x的排名(中转站)
    Re ans=0;
    for(Re i=R;i;i-=i&-i)ans+=ask_level(pt[i],1,m,w);
    for(Re i=L-1;i;i-=i&-i)ans-=ask_level(pt[i],1,m,w);
    return ans;
}
int main(){
//  printf("%lf\n",(sizeof(tree))/1024.0/1024.0);
//  printf("%lf\n",(sizeof(tree)+sizeof(Q)+sizeof(c)+sizeof(a)+sizeof(b)+sizeof(pt)+sizeof(C))/1024.0/1024.0);
    in(n),in(T),m=n;
    F(i,1,n)in(a[i]),b[i]=a[i];
    F(i,1,T){
        in(opt[i]);
        if(opt[i]==3)in(c[i].i),in(c[i].x),b[++m]=c[i].x;
        else{
            in(Q[i].l),in(Q[i].r),in(Q[i].k);
            if(opt[i]!=2)b[++m]=Q[i].k;//【不离散 WA上天】除了2的查询不用管,其他地方出现的k全部都要离散化
        }
    }
    sort(b+1,b+m+1);
    m=unique(b+1,b+m+1)-b-1;//unique()是-(b+1),lower_bound()是-b
    F(i,1,n)add_pre(i,1);//初始化建树
    F(i,1,T){
        if(opt[i]==1)//查询x的排名(中转站)
            Q[i].k=lo(Q[i].k),//【直接查询 WA上天】先查询Q[i].k在b中的的位置,将其减一查得 ≤他前一个数 的总个数
            printf("%d\n",ask_level_pre(Q[i].l,Q[i].r,Q[i].k-1)+1);//再加一查得Q[i].k的排名,酱紫可以有效避过Q[i].k的副本处理

        if(opt[i]==2)
            printf("%d\n",ask_kth_pre(Q[i].l,Q[i].r,Q[i].k));//查询第k小(中转站)

        if(opt[i]==3)//修改某一位值上的数值(中转站)
            add_pre(c[i].i,-1),a[c[i].i]=c[i].x,add_pre(c[i].i,1);
        //先让这个位置上原来的数减少一个,更新数字后再把新数加一个,就达到了替换的目的

        if(opt[i]==4){//查询前驱(严格小于)
/*1>取位置*/Q[i].k=lo(Q[i].k);//【直接查询 WA上天】先查询Q[i].k在b中的位置,将其位置减一查询得前驱
/*2>找排名*/Re level=ask_level_pre(Q[i].l,Q[i].r,Q[i].k-1);//因为在离散化数组中是找不到Q[i].k-1这个数字的,所以不能直接查询具体数值
/*3>判有无*/if(!level)printf("%d\n",-inf);//【判断条件错误 WA到上天】由于这里level是取出的前驱在b中的位置,所以只要【level>0】就可以啦
           //(如果你按着上面【直接查询 WA上天】的注释改了代码,却没有改这里的【条件判断】,那么你的level<=1将会让你【WA上天】)。
/*4>找结果*/else printf("%d\n",ask_kth_pre(Q[i].l,Q[i].r,level));
        }

        if(opt[i]==5){//查询猴急(严格大于)【盲目复制 WA上天】如果你采用了同上的方法,等着死翘翘吧
/*1>取位置*/Q[i].k=lo(Q[i].k);
/*2>找排名*/Re level=ask_level_pre(Q[i].l,Q[i].r,Q[i].k);//【直接查询 WA上天】如果同上,会越界,上面的越界是b[0]=0所以不慌,嘿嘿,而这里b[n+1]=0就不行了哟
/*3>判有无*/if(level==Q[i].r-Q[i].l+1)printf("%d\n",inf);//【判断条件错误 WA上天】这里猴急应是level+1,所以条件应是【level≤区间总长度】
/*4>找结果*/else printf("%d\n",ask_kth_pre(Q[i].l,Q[i].r,level+1));//【盲目复制 WA上天】 别忘了加一,和前驱不同啦!
        }
    }
}

3.【单修(点权),区查(Sum)】

【模板】 \(\text{Intersection of Permutations [CF1093E]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define Re register int
using namespace std;
const int N=2e5+3;char opt[N];
int x,y,z,w,n,T,op,A[N],rk[N];
inline void in(int &x){
    Re fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
int pt[N<<1];
struct Segment_Tree{
    #define pl tr[p].lp
    #define pr tr[p].rp
    #define mid ((L+R)>>1)
    int O;queue<int>Q;
    struct QAQ{int S,lp,rp;}tr[N*200];
    inline int New(){//新建节点
        if(Q.empty())return ++O;
        Re tmp=Q.front();Q.pop();
        return tmp;
    }
    inline void del(Re &p){pl=pr=0,Q.push(p),p=0;}//回收垃圾(注意取地址符并初始化为1)
    inline void change(Re &p,Re L,Re R,Re w,Re v){
        if(!p)p=New();tr[p].S+=v;
        if(L==R){if(!tr[p].S)del(p);return;}
        if(w<=mid)change(pl,L,mid,w,v);
        else change(pr,mid+1,R,w,v);
        if(!tr[p].S)del(p);
    }
    inline int ask(Re p,Re L,Re R,Re l,Re r){
        if(!p)return 0;
        if(l<=L&&R<=r)return tr[p].S;
        Re ans=0;
        if(l<=mid)ans+=ask(pl,L,mid,l,r);
        if(r>mid)ans+=ask(pr,mid+1,R,l,r);
        return ans;
    }
}TR;
inline int ask(Re L,Re R,Re l,Re r){
    Re ans=0;
    for(Re i=R;i;i-=i&-i)ans+=TR.ask(pt[i],1,n,l,r);
    for(Re i=L-1;i;i-=i&-i)ans-=TR.ask(pt[i],1,n,l,r);
    return ans;
}
inline void add(Re x,Re w,Re v){
    for(Re i=x;i<=n;i+=i&-i)TR.change(pt[i],1,n,w,v);
}
int main(){
//    freopen("123.txt","r",stdin);
    in(n),in(T);
    for(Re i=1;i<=n;++i)in(x),rk[x]=i;
    for(Re i=1;i<=n;++i)in(A[i]),A[i]=rk[A[i]],add(i,A[i],1);
    while(T--){
        in(op),in(x),in(y);
        if(op>1)add(x,A[x],-1),add(y,A[y],-1),swap(A[x],A[y]),add(x,A[x],1),add(y,A[y],1);
        else in(z),in(w),printf("%d\n",ask(z,w,x,y));
    }
}

七:【李超线段树】

【模板】 \(\text{Blue Mary}\) 开公司 \(\text{[JSOI2008]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define LD double
#define LL long long
#define Re register int
using namespace std;
const int N=1e5+3,M=5e4;
int n,x,T;LD b[N],k[N];char s[20];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline LD y(Re id,Re x){return k[id]*x+b[id];}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    int tr[N<<2];
    inline void change(Re p,Re L,Re R,Re id){
        if(y(id,L)>y(tr[p],L)&&y(id,R)>y(tr[p],R)){tr[p]=id;return;}
        if(y(id,L)<=y(tr[p],L)&&y(id,R)<=y(tr[p],R))return;
//        if(L==R){if(y(id,L)>y(tr[p],L))tr[p]=id;return;}
        if(k[tr[p]]<k[id]){
            if(y(id,mid+1)>y(tr[p],mid+1))change(pl,L,mid,tr[p]),tr[p]=id;
            else change(pr,mid+1,R,id);
        }
        else{
            if(y(id,mid)>y(tr[p],mid))change(pr,mid+1,R,tr[p]),tr[p]=id;
            else change(pl,L,mid,id);
        }
    }
    inline LD ask(Re p,Re L,Re R,Re x){
        if(L==R)return y(tr[p],x);
        LD ans=y(tr[p],x);
        if(x<=mid)return max(ans,ask(pl,L,mid,x));
        else return max(ans,ask(pr,mid+1,R,x));
    }
}TR;
int main(){
//    freopen("123.txt","r",stdin);
    in(T);
    while(T--){
        scanf("%s",s);
        if(s[0]=='P')++n,scanf("%lf%lf",&b[n],&k[n]),TR.change(1,1,M,n);
        else in(x),printf("%d\n",(int)(TR.ask(1,1,M,x-1)/100));
    }
}

八:【线段树分治(时间分治)】

1.【冰茶姬(判断二分图)】

【模板】 线段树分治 / 二分图 \(\text{[P5787]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<stack>
#include<map>
#define LL long long
#define Re register int
#define mp make_pair
using namespace std;
const int N=1e5+3,M=2e5+3;
int x,y,l,r,n,m,T,Ans[N];char ch[20];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Union{//冰茶姬
    struct BK{int x,y,sizex,sizey;BK(Re X=0,Re S1=0,Re Y=0,Re S2=0){x=X,y=Y,sizex=S1,sizey=S2;}};
    int fa[N<<1],size[N<<1];stack<BK>Q;
    inline int find(Re x){return fa[x]==x?x:find(fa[x]);}
    inline void merge(Re x,Re y){//按秩合并
        x=find(x),y=find(y);
        if(x==y)return;
        if(size[x]>size[y])swap(x,y);
        Q.push(BK(x,size[x],y,size[y]));
        fa[x]=y,size[y]+=size[x];
    }
    inline void back(Re to){//撤销操作
        while(int(Q.size())>to){
            BK a=Q.top();Q.pop();
            fa[a.x]=a.x,size[a.x]=a.sizex;
            fa[a.y]=a.y,size[a.y]=a.sizey;
        }
    }
}TF;
int o,head[N<<2];
struct QAQ{int x,y,next;}a[M*20];
inline void add(Re x,Re y1,Re y2){a[++o].x=y1,a[o].y=y2,a[o].next=head[x],head[x]=o;}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    inline void change(Re p,Re L,Re R,Re l,Re r,Re x,Re y){
        if(l>r)return;
        if(l<=L&&R<=r){add(p,x,y);return;}
        if(l<=mid)change(pl,L,mid,l,r,x,y);
        if(r>mid)change(pr,mid+1,R,l,r,x,y);
    }
    inline void dfs(Re p,Re L,Re R){
        Re tmp=TF.Q.size();
        for(Re i=head[p];i;i=a[i].next){
            if(TF.find(a[i].x)==TF.find(a[i].y)){
                for(Re j=L;j<=R;++j)Ans[j]=1;
                TF.back(tmp);return;
            }
            TF.merge(a[i].x,a[i].y+n),TF.merge(a[i].x+n,a[i].y);
        }
        if(L<R)dfs(pl,L,mid),dfs(pr,mid+1,R);
        TF.back(tmp);//回退
    }
}T1;
int main(){
//    freopen("123.txt","r",stdin);
    in(n),in(m),in(T);
    for(Re i=1;i<=(n<<1);++i)TF.fa[i]=i,TF.size[i]=1;
    for(Re i=1;i<=m;++i)in(x),in(y),in(l),in(r),T1.change(1,1,T,l+1,r+1-1,x,y);
    T1.dfs(1,1,T);
    for(Re i=1;i<=T;++i)puts(Ans[i]?"No":"Yes");
}

2.【冰茶姬(查询图的连通性)】

【模板】 洞穴勘测 \(\text{[SDOI2008] [P2147]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<stack>
#include<map>
#define LL long long
#define Re register int
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=1e4+3,M=2e5+3;
int x,y,n,T,Ans[M];char ch[20];
map<pair<int,int>,int>last;
struct Query{int x,y,op;}Q[M];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Union{//冰茶姬
    struct BK{int x,y,sizex,sizey;BK(Re X=0,Re S1=0,Re Y=0,Re S2=0){x=X,y=Y,sizex=S1,sizey=S2;}};
    int fa[N],size[N];stack<BK>Q;
    inline int find(Re x){return fa[x]==x?x:find(fa[x]);}
    inline void merge(Re x,Re y){//按秩合并
        x=find(x),y=find(y);
        if(size[x]>size[y])swap(x,y);
        Q.push(BK(x,size[x],y,size[y]));
        fa[x]=y,size[y]+=size[x];
    }
    inline void back(Re to){//撤销操作
        while(Q.size()>to){
            BK a=Q.top();Q.pop();
            fa[a.x]=a.x,size[a.x]=a.sizex;
            fa[a.y]=a.y,size[a.y]=a.sizey;
        }
    }
}TF;
int o,head[M<<2];
struct QAQ{int x,y,next;}a[M*20];
inline void add(Re x,Re y1,Re y2){a[++o].x=y1,a[o].y=y2,a[o].next=head[x],head[x]=o;}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid (L+R>>1)
    inline void change(Re p,Re L,Re R,Re l,Re r,Re x,Re y){
        if(l<=L&&R<=r){add(p,x,y);return;}
        if(l<=mid)change(pl,L,mid,l,r,x,y);
        if(r>mid)change(pr,mid+1,R,l,r,x,y);
    }
    inline void dfs(Re p,Re L,Re R){
        Re tmp=TF.Q.size();
        for(Re i=head[p];i;i=a[i].next)TF.merge(a[i].x,a[i].y);
        if(L==R){if(Q[L].op)Ans[L]=(TF.find(Q[L].x)==TF.find(Q[L].y));}
        else dfs(pl,L,mid),dfs(pr,mid+1,R);
        TF.back(tmp);//回退
    }
}T1;
int main(){
//    freopen("123.txt","r",stdin);
    in(n),in(T);
    for(Re i=1;i<=n;++i)TF.fa[i]=i,TF.size[i]=1;
    for(Re i=1;i<=T;++i){
        scanf("%s",ch),in(x),in(y);if(x>y)swap(x,y);
        if(ch[0]=='Q')Q[i].op=1,Q[i].x=x,Q[i].y=y;
        else if(ch[0]=='C')last[mp(x,y)]=i;
        else T1.change(1,1,T,last[mp(x,y)],i,x,y),last.erase(mp(x,y));
    }
    for(map<pair<int,int>,int>::iterator it=last.begin();it!=last.end();++it)
        T1.change(1,1,T,it->second,T,it->first.first,it->first.second);
    T1.dfs(1,1,T);
    for(Re i=1;i<=T;++i)if(Q[i].op)puts(Ans[i]?"Yes":"No");
}

3.【线性基】

【模板】 八纵八横 \(\text{[HAOI2017] [P3733]}\)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<stack>
#define LL long long
#define Re register int
#define Int bitset<M>
using namespace std;
const int N=550+5,M=1000+5;
int n,m,x,y,o,O,T,logN,X[N],Y[N],fa[N],last[N],head[N];Int z,Z[N],dis[N],Ans[M];char op[20];
struct QAQ{int to,next;Int w;}a[N<<1];
inline void add(Re x,Re y,Int z){a[++o].to=y,a[o].w=z,a[o].next=head[x],head[x]=o;}
inline int find(Re x){return x==fa[x]?x:fa[x]=find(fa[x]);}
inline int getlen(Int &x){Re n=1000;while(n>=1&&!x[n])--n;return n;}
inline void print(Int &x){for(Re i=getlen(x);i>=0;--i)putchar(x[i]+'0');puts("");}
inline void in(Int &x){cin>>x,logN=max(logN,getlen(x));}
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Line_JI{
    Int p[M];bool pp[M];stack<int>Q;
    inline void insert(Int x){
        for(Re i=logN;i>=0;--i)
            if(x[i]){
                if(!pp[i]){Q.push(i),p[i]=x,pp[i]=1;break;}
                x^=p[i];
            }
    }
    inline Int ask(){
        Int ans;ans.reset();
        for(Re i=logN;i>=0;--i)if(pp[i]&&(!ans[i]))ans^=p[i];
        return ans;
    }
    inline void back(Re to){
        while(Q.size()>to)x=Q.top(),Q.pop(),p[x].reset(),pp[x]=0;
    }
}JI;
struct Segment_Tree{
    int o,head[M<<2];
    struct QAQ{int x,y,next;Int w;}a[(N+M)*10];
    inline void add(Re t,Re x,Re y,Int &z){a[++o].x=x,a[o].y=y,a[o].w=z,a[o].next=head[t],head[t]=o;}
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    inline void change(Re p,Re L,Re R,Re l,Re r,Re x,Re y,Int &z){
        if(l<=L&&R<=r){add(p,x,y,z);return;}
        if(l<=mid)change(pl,L,mid,l,r,x,y,z);
        if(r>mid)change(pr,mid+1,R,l,r,x,y,z);
    }
    inline void dfs(Re p,Re L,Re R){
        Re tmp=JI.Q.size();
        for(Re i=head[p];i;i=a[i].next)JI.insert(dis[a[i].x]^dis[a[i].y]^a[i].w);
        if(L==R)Ans[L]=JI.ask();//这里还没调用back进行撤回,不能return啊!!!
        else dfs(pl,L,mid),dfs(pr,mid+1,R);
        JI.back(tmp);
    }
}TR;
inline void dfs(Re x,Re fa,Re w){
    dis[x]=dis[fa]^a[w].w;
    for(Re i=head[x];i;i=a[i].next)
        if(a[i].to!=fa)dfs(a[i].to,x,i);
}
int main(){
//    freopen("123.txt","r",stdin);
    in(n),in(m),in(T),++T;
    for(Re i=1;i<=n;++i)fa[i]=i;
    while(m--){
        in(x),in(y),in(z);
        if(find(x)!=find(y))add(x,y,z),add(y,x,z),fa[find(x)]=find(y);
        else TR.change(1,1,T,1,T,x,y,z);
    }
    for(Re i=2;i<=T;++i){
        scanf("%s",op);
        if(op[0]=='A')last[++O]=i,in(X[O]),in(Y[O]),in(Z[O]);
        else if(op[1]=='h'){
            in(x),in(z);
            TR.change(1,1,T,last[x],i-1,X[x],Y[x],Z[x]);
            last[x]=i,Z[x]=z;
        }
        else in(x),TR.change(1,1,T,last[x],i-1,X[x],Y[x],Z[x]),last[x]=0;
    }
    for(Re i=1;i<=O;++i)if(last[i])TR.change(1,1,T,last[i],T,X[i],Y[i],Z[i]);
    dfs(1,0,0),TR.dfs(1,1,T);
    for(Re i=1;i<=T;++i)print(Ans[i]);
}

4.【LCT(维护 MST)】

【模板】 城市建设 \(\text{[HNOI2010] [P3206]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=2e4+3,M=5e4+3;
int n,m,x,y,z,T,op,X[N+M],Y[N+M],last[M];LL v[N+M],Ans[M];
inline void in(int &x){
    Re fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
struct QWQ{int id,op;QWQ(Re ID=0,Re OP=0){id=ID,op=OP;}};
struct Link_Cut_Tree{
    #define pl tr[p].ps[0]
    #define pr tr[p].ps[1]
    #define pf tr[p].fa
    int size,Q[N+M];QWQ QQ[M*32];LL MST;
    struct QAQ{int mx,fa,tag,ps[2];}tr[N+M];
    inline void pushup(Re p){
        tr[p].mx=p;
        if(pl&&v[tr[pl].mx]>v[tr[p].mx])tr[p].mx=tr[pl].mx;
        if(pr&&v[tr[pr].mx]>v[tr[p].mx])tr[p].mx=tr[pr].mx;
    }
    inline void updata(Re p){swap(pl,pr),tr[p].tag^=1;}
    inline void pushdown(Re p){
        if(tr[p].tag){
            if(pl)updata(pl);
            if(pr)updata(pr);
            tr[p].tag=0;
        }
    }
    inline int which(Re p){return tr[pf].ps[1]==p;}
    inline int nort(Re p){return tr[pf].ps[0]==p||tr[pf].ps[1]==p;}
    inline void connect(Re p,Re fa,Re o){tr[pf=fa].ps[o]=p;}
    inline void rotate(Re p){
        Re fa=pf,fas=which(p);
        Re pa=tr[fa].fa,pas=which(fa);
        Re x=tr[p].ps[fas^1];
        if(nort(fa))tr[pa].ps[pas]=p;pf=pa;
        connect(x,fa,fas),connect(fa,p,fas^1);
        pushup(fa),pushup(p); 
    }
    inline void splay(Re p){
        Re x=p,t=0;Q[++t]=x;
        while(nort(x))Q[++t]=x=tr[x].fa;
        while(t)pushdown(Q[t--]);
        for(Re fa;nort(p);rotate(p))
            if(nort(fa=pf))rotate(which(p)==which(fa)?fa:p);
    }
    inline void access(Re p){
        for(Re son=0;p;son=p,p=pf)
            splay(p),pr=son,pushup(p);
    }
    inline void makeroot(Re x){access(x),splay(x),updata(x);}
    inline int findroot(Re p){
        access(p),splay(p),pushdown(p);
        while(pl)pushdown(p=pl);
        return p;
    }
    inline void split(Re x,Re y){makeroot(x),access(y),splay(y);}
    inline void link(Re x,Re y){makeroot(x),tr[x].fa=y;}
    inline void cut(Re x,Re y){makeroot(x),access(y),splay(y),tr[x].fa=tr[y].ps[0]=0,pushup(y);}
    inline void cut_(Re id){
        makeroot(Y[id]),access(X[id]),splay(X[id]),tr[X[id]].ps[0]=tr[Y[id]].fa=tr[id].ps[0]=tr[id].fa=0,pushup(X[id]);
    }
    inline void link_(Re id){
        makeroot(X[id]),makeroot(Y[id]),tr[X[id]].fa=tr[Y[id]].fa=id;
    }
    inline void MST_link(Re id){
        Re x=X[id],y=Y[id];makeroot(x);
        if(findroot(y)!=x)link(x,id),link(id,y),QQ[++size]=QWQ(id,0),MST+=v[id];
        else{
            Re mx=tr[y].mx;
            if(v[id]<v[mx]){
//                cut(X[mx],mx),cut(mx,Y[mx]),QQ[++size]=QWQ(mx,1);
                cut_(mx),QQ[++size]=QWQ(mx,1);
                link(x,id),link(id,y),QQ[++size]=QWQ(id,0);
//                link_(id),QQ[++size]=QWQ(id,0);
                MST+=v[id]-v[mx];
            }
        }
    }
    inline void back(Re to){
        while(size>to){
            QWQ a=QQ[size--];Re id=a.id;
            if(a.op)link(id,Y[id]),link(X[id],id),MST+=v[id];
//            else cut(id,Y[id]),cut(X[id],id),MST-=v[id];
//            if(a.op)link_(id),MST+=v[id];
            else cut_(id),MST-=v[id];
        }
    }
    #undef pl
    #undef pr
}LCT;
int o,head[M<<2];
struct QAQ{int id,next;LL v;}a[M*32];
inline void add(Re x,Re id,LL v){a[++o].id=id,a[o].v=v,a[o].next=head[x],head[x]=o;}
struct Segment_Tree{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    inline void change(Re p,Re L,Re R,Re l,Re r,Re id,LL v){
        if(l>r)return;
        if(l<=L&&R<=r){add(p,id,v);return;}
        if(l<=mid)change(pl,L,mid,l,r,id,v);
        if(r>mid)change(pr,mid+1,R,l,r,id,v);
    }
    inline void dfs(Re p,Re L,Re R){
        Re tmp=LCT.size;
        for(Re i=head[p];i;i=a[i].next)v[a[i].id]=a[i].v,LCT.MST_link(a[i].id);
        if(L==R)Ans[L]=LCT.MST;
        else dfs(pl,L,mid),dfs(pr,mid+1,R);
        LCT.back(tmp);
    }
}T1;
int main(){
//     freopen("123.txt","r",stdin);
//     freopen("my.txt","w",stdout);
    in(n),in(m),in(T);
    for(Re i=1;i<=m;++i)in(X[i+n]),in(Y[i+n]),in(x),v[i+n]=x,last[i]=1;
    for(Re i=1;i<=T;++i){
        in(x),in(y);
        T1.change(1,1,T,last[x],i-1,x+n,v[x+n]);
        last[x]=i,v[x+n]=y;
    }
    for(Re i=1;i<=m;++i)T1.change(1,1,T,last[i],T,i+n,v[i+n]);
    T1.dfs(1,1,T);
    for(Re i=1;i<=T;++i)printf("%lld\n",Ans[i]);
}

九:【线段树优化建图】

【模板整合计划】图论


-----若要转载请私信作者获得许可并在文首标出转载来源-----

posted @ 2019-10-21 19:56  辰星凌  阅读(359)  评论(0编辑  收藏  举报