线段树
普通线段树
P3372 【模板】线段树 1:区间加&区间求和
Code
#include<iostream>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=1e5+5;
int n,m;
long long a[N];
struct Segment_Tree
{
long long Tree[N<<2],lazy[N<<2];
void Pushup(int k)
{
Tree[k]=Tree[k<<1]+Tree[k<<1|1];
}
void Pushdown(int k,int L,int R)
{
if(!lazy[k]) return;
int Mid=(L+R)>>1;
Tree[k<<1]+=lazy[k]*(Mid-L+1);
lazy[k<<1]+=lazy[k];
Tree[k<<1|1]+=lazy[k]*(R-Mid);
lazy[k<<1|1]+=lazy[k];
lazy[k]=0;
}
void Buildtree(int k,int L,int R)
{
if(L==R)
{
Tree[k]=a[L];
return;
}
int Mid=(L+R)>>1;
Buildtree(k<<1,L,Mid);
Buildtree(k<<1|1,Mid+1,R);
Pushup(k);
}
void Modify(int k,int L,int R,int ql,int qr,long long val)
{
if(ql<=L&&R<=qr)
{
Tree[k]+=val*(R-L+1);
lazy[k]+=val;
return;
}
Pushdown(k,L,R);
int Mid=(L+R)>>1;
if(ql<=Mid)
Modify(k<<1,L,Mid,ql,qr,val);
if(qr>Mid)
Modify(k<<1|1,Mid+1,R,ql,qr,val);
Pushup(k);
}
long long Query(int k,int L,int R,int ql,int qr)
{
if(ql<=L&&R<=qr)
return Tree[k];
Pushdown(k,L,R);
int Mid=(L+R)>>1;
long long res=0;
if(ql<=Mid)
res=res+Query(k<<1,L,Mid,ql,qr);
if(qr>Mid)
res=res+Query(k<<1|1,Mid+1,R,ql,qr);
return res;
}
}Segment;
int main()
{
IOS;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
Segment.Buildtree(1,1,n);
while(m--)
{
int opt,L,R;
long long val;
cin>>opt>>L>>R;
if(opt==1) cin>>val,Segment.Modify(1,1,n,L,R,val);
else cout<<Segment.Query(1,1,n,L,R)<<'\n';
}
return 0;
}
线段树二分
Analysis
对于每一个 \(i\),我们需要找到其作为最小值能够影响到的范围 \([m_i,n_i]\),对答案加上 \(a_i \times (i-m_i) \times (n_i-i)\) 的贡献,使用线段树优化二分查找的过程。在查找 \(m_i\) 时,若 \(a_i \le \operatorname{min}(mid,r)\),则 \(m_i\) 更新为 \(mid\),同时继续向左扩展,求 \(n_i\) 时也是同理。
Code
#include<iostream>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=1e5+5;
int n,a[N];
long long ans=0;
struct Segment_Tree
{
int Tree[N<<2];
void Pushup(int k)
{
Tree[k]=min(Tree[k<<1],Tree[k<<1|1]);
}
void Buildtree(int k,int L,int R)
{
if(L==R)
{
Tree[k]=a[L];
return;
}
int Mid=(L+R)>>1;
Buildtree(k<<1,L,Mid);
Buildtree(k<<1|1,Mid+1,R);
Pushup(k);
}
int Query(int k,int L,int R,int ql,int qr)
{
if(ql<=L&&R<=qr)
return Tree[k];
int res=0x3f3f3f3f,Mid=(L+R)>>1;
if(ql<=Mid)
res=min(res,Query(k<<1,L,Mid,ql,qr));
if(qr>Mid)
res=min(res,Query(k<<1|1,Mid+1,R,ql,qr));
return res;
}
}Segment;
int main()
{
IOS;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
Segment.Buildtree(1,1,n);
for(int i=1;i<=n;i++)
{
int L=1,R=i,ans1=R,ans2;
while(L<=R)
{
int Mid=(L+R)>>1;
if(a[i]<=Segment.Query(1,1,n,Mid,i))
ans1=Mid,R=Mid-1;
else
L=Mid+1;
}
L=i,R=n,ans2=L;
while(L<=R)
{
int Mid=(L+R)>>1;
if(a[i]<=Segment.Query(1,1,n,i,Mid))
ans2=Mid,L=Mid+1;
else
R=Mid-1;
}
ans+=1ll*a[i]*(i-ans1+1)*(ans2-i+1);
}
cout<<ans<<'\n';
return 0;
}
权值线段树
Code
#include<iostream>
#include<algorithm>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=1e5+5;
struct Segment_Tree
{
int Tree[N<<2];
void Pushup(int k)
{
Tree[k]=Tree[k<<1]+Tree[k<<1|1];
}
void Modify(int k,int L,int R,int pos,int val)
{
if(L==R)
{
Tree[k]+=val;
return;
}
int Mid=(L+R)>>1;
if(pos<=Mid)
Modify(k<<1,L,Mid,pos,val);
if(pos>Mid)
Modify(k<<1|1,Mid+1,R,pos,val);
Pushup(k);
}
int Query(int k,int L,int R,int ql,int qr)
{
if(ql>qr) return 0;
if(ql<=L&&R<=qr)
return Tree[k];
int res=0,Mid=(L+R)>>1;
if(ql<=Mid)
res=res+Query(k<<1,L,Mid,ql,qr);
if(qr>Mid)
res=res+Query(k<<1|1,Mid+1,R,ql,qr);
return res;
}
int Query_val(int k,int L,int R,int rank)
{
if(L==R) return L;
int Mid=(L+R)>>1;
if(rank<=Tree[k<<1])
return Query_val(k<<1,L,Mid,rank);
else
return Query_val(k<<1|1,Mid+1,R,rank-Tree[k<<1]);
}
int Predecessor(int siz,int val)
{
int cnt=Query(1,1,siz,1,val-1);
if(cnt==0) return 0;
return Query_val(1,1,siz,cnt);
}
int Successor(int siz,int val)
{
int cnt=Query(1,1,siz,1,val);
if(cnt==Tree[1]) return 0;
return Query_val(1,1,siz,cnt+1);
}
}Segment;
struct Node
{
int opt;
int x;
}Ques[N];
int n,siz,Hash[N];
int main()
{
IOS;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>Ques[i].opt>>Ques[i].x;
if(Ques[i].opt!=4) Hash[++siz]=Ques[i].x;
}
sort(Hash+1,Hash+siz+1);
siz=unique(Hash+1,Hash+siz+1)-(Hash+1);
for(int i=1;i<=n;i++)
{
if(Ques[i].opt==4) continue;
Ques[i].x=lower_bound(Hash+1,Hash+siz+1,Ques[i].x)-Hash;
}
for(int i=1;i<=n;i++)
{
if(Ques[i].opt==1)
Segment.Modify(1,1,siz,Ques[i].x,1);
else if(Ques[i].opt==2)
Segment.Modify(1,1,siz,Ques[i].x,-1);
else if(Ques[i].opt==3)
cout<<Segment.Query(1,1,siz,1,Ques[i].x-1)+1<<'\n';
else if(Ques[i].opt==4)
cout<<Hash[Segment.Query_val(1,1,siz,Ques[i].x)]<<'\n';
else if(Ques[i].opt==5)
cout<<Hash[Segment.Predecessor(siz,Ques[i].x)]<<'\n';
else
cout<<Hash[Segment.Successor(siz,Ques[i].x)]<<'\n';
}
return 0;
}
浙公网安备 33010602011771号