【模板整合计划】高阶数据结构—线段树
【模板整合计划】高阶数据结构—线段树
一:【基本操作及扩展】
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.【面积】
#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】
#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).【分裂指定区间】
#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]);
}
九:【线段树优化建图】
见 【模板整合计划】图论 。