目录
- 单点赋值,区间求最大值
- 区间加,区间求和
- 区间加、乘,区间求和
- 权值线段树
- 动态开点线段树
- 主席树
- 线段树优化建图
- 扫描线
单点赋值,区间求最大值
返回顶部
#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;
}