线段树模版总结

目录

  1. 单点赋值,区间求最大值
  2. 区间加,区间求和
  3. 区间加、乘,区间求和
  4. 权值线段树
  5. 动态开点线段树
  6. 主席树
  7. 线段树优化建图
  8. 扫描线

单点赋值,区间求最大值

返回顶部

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,INF=0x3f3f3f3f3f3f3f3f;
int a[N],n;
struct node{int l,r,num;}tree[N*4];
void build(int p,int l,int r)//建树 
{
    tree[p].l=l;tree[p].r=r;
    if(l==r)
    {
    	tree[p].num=a[l];
    	return ;
	}
    int mid=(l+r)/2;
    build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	tree[p].num=max(tree[p*2].num,tree[p*2+1].num); 
}
void change(int p,int x,int v)//单点赋值 
{
	if(tree[p].l==tree[p].r)
	{
		tree[p].num=v;
		return ;
	}
	int mid=(tree[p].l+tree[p].r)/2;
	if(x<=mid) change(p*2,x,v);
	else change(p*2+1,x,v);
	tree[p].num=max(tree[p*2].num,tree[p*2+1].num);
}
int ask(int p,int l,int r)//区间查询
{
	if(l<=tree[p].l&&r>=tree[p].r) return tree[p].num;//完全包含该区间
	int mid=(tree[p].l+tree[p].r)/2;
	int res=-(1<<30);
	if(l<=mid) res=max(res,ask(p*2,l,r));
	if(r>=mid+1) res=max(res,ask(p*2+1,l,r));
	return res;
}
signed main()
{
	cin>>n;
//	for(int i=1;i<=n;i++)
//		cin>>a[i];
	build(1,1,n);
	for(int i=1;i<=n;i++)
	{
		int op,x,y;cin>>op>>x>>y;
		if(op==1)
		{
			change(1,x,y);
		}
		else
		{
			cout<<ask(1,x,y)<<'\n';
		}
	}
	return 0;
}

区间加,区间求和

返回顶部

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,INF=0x3f3f3f3f3f3f3f3f;
int a[N],n,q;
struct node{int l,r,sum,add;}tree[N*4];
void build(int p,int l,int r)//建树 
{
    tree[p].l=l;tree[p].r=r;
    if(l==r)
    {
    	tree[p].sum=a[l];
    	return ;
	}
    int mid=(l+r)/2;
    build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
}
void push_down(int p)//下放懒标记 
{
	if(tree[p].add)
	{
		tree[p*2].sum+=tree[p].add*(tree[p*2].r-tree[p*2].l+1);
		tree[p*2+1].sum+=tree[p].add*(tree[p*2+1].r-tree[p*2+1].l+1);
		tree[p*2].add+=tree[p].add;
		tree[p*2+1].add+=tree[p].add;
		tree[p].add=0;
	}
}
void change(int p,int l,int r,int d)//区间加 
{
	if(l<=tree[p].l&&r>=tree[p].r)
	{
		tree[p].sum+=d*(tree[p].r-tree[p].l+1);
		tree[p].add+=d;
		return ;
	}
	push_down(p);
	int mid=(tree[p].l+tree[p].r)/2;
	if(l<=mid) change(p*2,l,r,d);
	if(r>=mid+1) change(p*2+1,l,r,d);
	tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
}
int ask(int p,int l,int r)//区间查询 
{
	if(l<=tree[p].l&&r>=tree[p].r) return tree[p].sum;//完全包含该区间
	push_down(p);
	int mid=(tree[p].l+tree[p].r)/2;
	int res=0;
	if(l<=mid) res+=ask(p*2,l,r);
	if(r>=mid+1) res+=ask(p*2+1,l,r);
	return res;
}
signed main()
{
	cin>>n>>q;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	build(1,1,n);
	for(int i=1;i<=q;i++)
	{
		char op;cin>>op;
		if(op=='C')
		{
			int l,r,d;cin>>l>>r>>d;
			change(1,l,r,d);
		}
		else
		{
			int l,r;cin>>l>>r;
			cout<<ask(1,l,r)<<'\n';
		}
	}
	return 0;
}

区间加、乘,区间求和

返回顶部

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,INF=0x3f3f3f3f3f3f3f3f;
int a[N],n,q,mod;
struct node{int l,r,sum,add,mul;}tree[N*4];
void build(int p,int l,int r)//建树 
{
    tree[p].l=l;tree[p].r=r;tree[p].mul=1;
    if(l==r)
    {
    	tree[p].sum=a[l];
    	return ;
	}
    int mid=(l+r)/2;
    build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;tree[p].sum%=mod;
}
void apply_add(int p,int d)
{
	tree[p].sum+=d*(tree[p].r-tree[p].l+1);tree[p].sum%=mod;
	tree[p].add+=d;tree[p].add%=mod;
}
void apply_mul(int p,int d)
{
	tree[p].sum*=d;tree[p].sum%=mod;
	tree[p].mul*=d;tree[p].mul%=mod;
	tree[p].add*=d;tree[p].add%=mod;
}
void push_down(int p)//下放懒标记 
{
	if(tree[p].mul!=1)
	{
		apply_mul(p*2,tree[p].mul);
		apply_mul(p*2+1,tree[p].mul);
		tree[p].mul=1;
	}
	if(tree[p].add)
	{
		apply_add(p*2,tree[p].add);
		apply_add(p*2+1,tree[p].add);
		tree[p].add=0;
	}
}
void change_add(int p,int l,int r,int d)//区间加 
{
	if(l<=tree[p].l&&r>=tree[p].r)
	{
		apply_add(p,d);
		return ;
	}
	push_down(p);
	int mid=(tree[p].l+tree[p].r)/2;
	if(l<=mid) change_add(p*2,l,r,d);
	if(r>=mid+1) change_add(p*2+1,l,r,d);
	tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;tree[p].sum%=mod;
}
void change_mul(int p,int l,int r,int d)//区间乘 
{
	if(l<=tree[p].l&&r>=tree[p].r)
	{
		apply_mul(p,d);
		return ;
	}
	push_down(p);
	int mid=(tree[p].l+tree[p].r)/2;
	if(l<=mid) change_mul(p*2,l,r,d);
	if(r>=mid+1) change_mul(p*2+1,l,r,d);
	tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;tree[p].sum%=mod;
}
int ask(int p,int l,int r)//区间查询 
{
	if(l<=tree[p].l&&r>=tree[p].r) return tree[p].sum;//完全包含该区间
	push_down(p);
	int mid=(tree[p].l+tree[p].r)/2;
	int res=0;
	if(l<=mid) res+=ask(p*2,l,r);res%=mod;
	if(r>=mid+1) res+=ask(p*2+1,l,r);res%=mod;
	return res;
}
signed main()
{
	cin>>n>>mod;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	cin>>q;
	build(1,1,n);
	for(int i=1;i<=q;i++)
	{
		int op;cin>>op;
		if(op==1)
		{
			int l,r,d;cin>>l>>r>>d;
			change_mul(1,l,r,d);
		}
		else if(op==2)
		{
			int l,r,d;cin>>l>>r>>d;
			change_add(1,l,r,d);
		}
		else
		{
			int l,r;cin>>l>>r;
			cout<<ask(1,l,r)<<'\n';
		}
	}
	return 0;
}

权值线段树

返回顶部

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,INF=0x3f3f3f3f3f3f3f3f;
int n,rk[N],ans[N],f[N];
struct node{int l,r,sum;}tree[N*4];
void build(int p,int l,int r)//建树 
{
    tree[p].l=l;tree[p].r=r;tree[p].sum=r-l+1;
    if(l==r) return ;
    int mid=(l+r)/2;
    build(p*2,l,mid);
	build(p*2+1,mid+1,r);
}
int ask(int p,int x)//区间查询 
{
	tree[p].sum--;
	if(tree[p].l==tree[p].r) return tree[p].l;//完全包含该区间
	if(tree[p*2].sum>=x) return ask(p*2,x);
	else return ask(p*2+1,x-tree[p*2].sum);
}
signed main()
{
	cin>>n;
	build(1,1,n);
	rk[1]=1;
	for(int i=2;i<=n;i++)
	{
		cin>>rk[i];
		rk[i]++;
	}
	for(int i=n;i>=1;i--)
	{
		ans[i]=ask(1,rk[i]);
//		int sum=0;
//		for(int j=1;j<=n;j++)
//		{
//			if(f[j]==1) continue;
//			sum++;
//			if(sum==rk[i])
//			{
//				ans[i]=j;
//				f[j]=1;
//			}
//		}
	}
	for(int i=1;i<=n;i++)
		cout<<ans[i]<<'\n';
	return 0;
}

动态开点线段树

返回顶部

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,INF=0x3f3f3f3f3f3f3f3f;
int n,cnt,rt;
struct node{int lc,rc,lz;}tree[N*20];
void change(int &p,int l,int r,int ql,int qr,int k)
{
	if(p==0) p=++cnt;
	if(ql<=l&&r<=qr)
	{
		tree[p].lz=max(tree[p].lz,k);
		return ;
	}
	int mid=(l+r)/2;
	if(ql<=mid) change(tree[p].lc,l,mid,ql,qr,k);
	if(qr>=mid+1) change(tree[p].rc,mid+1,r,ql,qr,k);
}
int ask(int p,int l,int r,int maxx)
{
	if(p==0) return maxx*(r-l+1);
	maxx=max(maxx,tree[p].lz);
	if(l==r) return maxx;
	int mid=(l+r)/2;
	return ask(tree[p].lc,l,mid,maxx)+ask(tree[p].rc,mid+1,r,maxx);
}
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int a,b,k;cin>>a>>b>>k;
		if(a>b-1) continue;
		change(rt,1,N*20,a,b-1,k);
	}
	cout<<ask(rt,1,N*20,0)<<'\n';
	return 0;
}

主席树

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,INF=0x3f3f3f3f3f3f3f3f;
int tot,ls[N],rs[N],sum[N],rt[N];
int update(int pre,int l,int r,int pos,int v)
{//在旧版本 pre 基础上,把位置 pos 的值改成 v,返回"新版本"的根
	int u=++tot;//开一个新节点
	ls[u]=ls[pre];rs[u]=rs[pre];sum[u]=sum[pre];//先把旧节点整份复制过来 
	if(l==r)
	{
		sum[u]=v;//走到叶子:直接改这个值
		return u;
	}
	int mid=(l+r)/2;
	if(pos<=mid)ls[u]=update(ls[pre],l,mid,pos,v);//只往下建"左半"这条链
	else rs[u]=update(rs[pre],mid+1,r,pos,v);//或"右半"这条链。 
	sum[u]=sum[ls[u]]+sum[rs[u]];        
	return u;
}
int query(int u,int l,int r,int ql,int qr)
{
	if(ql<=l&&r<=qr) return sum[u];//整个区间都被问到,直接返回
	int mid=(l+r)/2;
	int res=0;
	if(ql<=mid) res+=query(ls[u],l,mid,ql,qr);
	if(qr>mid) res+=query(rs[u],mid+1,r,ql,qr);
	return res;
}
signed main()
{
	return 0;
}

线段树优化建图

#include<bits/stdc++.h> 
#define int long long
#define pr pair<int,int>
using namespace std;
const int N=2e5+5,D=N*4,INF=0x3f3f3f3f3f3f3f3f;
int n,q,leaf[N];//记录每个原图点对应的叶子编号
vector<pr>g[N*9];
void add(int x,int y,int v)
{
	g[x].push_back({y,v});
}
void build(int p,int l,int r)
{
	if(l==r)
	{
		leaf[l]=p;
		return ;
	}
	int mid=(l+r)>>1;
	add(p,p*2,0);add(p,p*2+1,0);
	add(p*2+D,p+D,0);add(p*2+1+D,p+D,0);
	build(p*2,l,mid);build(p*2+1,mid+1,r);
}
void dtoq(int p,int l,int r,int ql,int qr,int x,int v)//x向[ql,qr]连边权为v的边 
{
	if(ql<=l&&r<=qr)
	{
		add(x,p,v);
		return ;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) dtoq(p*2,l,mid,ql,qr,x,v);
	if(qr>mid) dtoq(p*2+1,mid+1,r,ql,qr,x,v);
}
void qtod(int p,int l,int r,int ql,int qr,int x,int v)//[ql,qr]向x连边权为v的边
{
	if(ql<=l&&r<=qr)
	{
		add(p+D,x+D,v);
		return ;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) qtod(p*2,l,mid,ql,qr,x,v);
	if(qr>mid) qtod(p*2+1,mid+1,r,ql,qr,x,v);
}
void qtoq(int l1,int r1,int l2,int r2,int v)//[l1,r1]->[l2,r2],v
{
	int p=++tot;
	qtod(1,1,n,l2,r2,p,v);
	dtoq(1,1,n,l1,r1,p,0);
}
signed main()
{
	cin>>n>>q;
	build(1,1,n);
	for(int i=1;i<=n;i++)
	{
		add(leaf[i],leaf[i]+D,0);
		add(leaf[i]+D,leaf[i],0);
	}
	for(int i=1;i<=q;i++)
	{
		int op;cin>>op;
		if(op==1)//点->点 
		{
			int x,y,v;cin>>x>>y>>v;
			add(leaf[x],leaf[y],v);
			add(leaf[x]+D,leaf[y]+D,v);
		}
		else if(op==2)//点->区间 
		{
			int x,l,r,v;cin>>x>>l>>r>>v;
			dtoq(1,1,n,l,r,leaf[x],v);
		}
		else if(op==3)//区间->点 
		{
			int x,l,r,v;cin>>x>>l>>r>>v;
			qtod(1,1,n,l,r,leaf[x],v);
		}
		else
		{
			int l1,r1,l2,r2;cin>>l1>>r1>>l2>>r2;
			qtoq(l1,r1,l2,r2);
		}
	}
	return 0;
}

扫描线

返回顶部

模版题:

#include<bits/stdc++.h>
#define int long long
#define db double 
#define qy(FILE) freopen(FILE".in","r",stdin);freopen(FILE".out","w",stdout);
using namespace std;
const int N=2e5+5,INF=0x3f3f3f3f3f3f3f3f;
int n,m,cnt[N*4];
vector<db>b;
db ans,len[N*4];
struct node{int k,lsy1,lsy2;db yy1,yy2,x;}line[N];
bool cmp(node x,node y){return x.x<y.x;}
void add(int x,int l,int r,int ql,int qr,int d)
{
	if(ql<=l&&r<=qr)
	{
		cnt[x]+=d;
		if(cnt[x]) len[x]=b[r+1]-b[l];
		else len[x]=len[x*2]+len[x*2+1];
		return ;
	}
	int mid=(l+r)/2;
	if(ql<=mid) add(x*2,l,mid,ql,qr,d);
	if(qr>mid) add(x*2+1,mid+1,r,ql,qr,d);
	if(cnt[x]==0) len[x]=len[x*2]+len[x*2+1];
}
signed main()
{
//	qy("q");
	cin>>n;
	if(!n) return 0;
	for(int i=1;i<=n;i++)
	{
		db x1,yy1,x2,yy2;cin>>x1>>yy1>>x2>>yy2;
		line[i].x=x1;line[i].yy1=yy1;line[i].yy2=yy2;line[i].k=1;b.push_back(yy1);
		line[i+n].x=x2;line[i+n].yy1=yy1;line[i+n].yy2=yy2;line[i+n].k=-1;b.push_back(yy2);
	}
	sort(b.begin(),b.end());
	m=unique(b.begin(),b.end())-b.begin();
	sort(line+1,line+1+2*n,cmp);
	for(int i=1;i<=2*n;i++)
	{
		line[i].lsy1=lower_bound(b.begin(),b.begin()+m,line[i].yy1)-b.begin();
		line[i].lsy2=lower_bound(b.begin(),b.begin()+m,line[i].yy2)-b.begin()-1;
		add(1,0,m-1,line[i].lsy1,line[i].lsy2,line[i].k);
		if(i!=2*n) ans+=len[1]*(line[i+1].x-line[i].x);
	}
	cout<<fixed<<setprecision(2)<<ans<<'\n';
	return 0;
}


posted @ 2026-10-26 17:17  hemingxi_2030  阅读(6)  评论(0)    收藏  举报