将写一篇比较长的博客来系统的学习下线段树:群友Limit的线段树题单以及线段树分治的某些题单
update:群友Limit的线段树题单two
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll Tree[N<<4],w[N],lazy[N<<4];
//分别表示该节点的下的权值和是多少,
void pushdown(int u,int l,int r)
{
int mid=(l+r)>>1;
Tree[u<<1]+=(mid-l+1)*lazy[u];
Tree[u<<1|1]+=(r-mid)*lazy[u];
lazy[u<<1]+=lazy[u];
lazy[u<<1|1]+=lazy[u];
lazy[u]=0;
}
void modify(int u,int l,int r,int L,int R,int val)//在[l,r]中更新[L,R].
{
int mid=(l+r)>>1;
if(L>r||R<l) return;
if(L<=l&&r<=R) //这个区间信息可以保留.
{
lazy[u]+=val;
Tree[u]+=(r-l+1)*val;
return;
}
pushdown(u,l,r);
modify(u<<1,l,mid,L,R,val);
modify(u<<1|1,mid+1,r,L,R,val);
Tree[u]=Tree[u<<1]+Tree[u<<1|1];
}
ll query(int u,int l,int r,int L,int R)//在[l,r]中查询[L,R].
{
int mid=(l+r)>>1;
if(L>r||R<l) return 0;
pushdown(u,l,r);
if(L<=l&&r<=R) //这个区间信息可以保留.
{
return Tree[u];
}
return query(u<<1,l,mid,L,R)+query(u<<1|1,mid+1,r,L,R);
}
void build(int u,int l,int r)
{
if(l==r)
{
Tree[u]=w[l];
return;
}int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
Tree[u]=Tree[u<<1]+Tree[u<<1|1];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&w[i]);
}build(1,1,n);
for(int i=1;i<=m;i++)
{
int op,x,y,k;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&x,&y,&k);
modify(1,1,n,x,y,k);
}
else
{
scanf("%d%d",&x,&y);
printf("%lld\n",query(1,1,n,x,y));
}
}
return 0;
}
P6492 [COCI2010-2011#6] STEP
吐槽:为什么我的代码如此优美呢?2333
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+50;
struct Tree{
int l,r,L,R,lans,rans,ans;//l,r表示管辖的范围.L,R表示该节点左右两端的值.ans表示最长的长度.
}tr[N<<2];
void push_up(int u)
{
int ls=(u<<1),rs=(u<<1|1);
tr[u].ans=max(tr[ls].ans,tr[rs].ans);
tr[u].lans=tr[ls].lans;
tr[u].rans=tr[rs].rans;
if(tr[ls].R^tr[rs].L)
{
tr[u].ans=max(tr[u].ans,tr[ls].rans+tr[rs].lans);
if(tr[ls].lans==(tr[ls].r-tr[ls].l+1)) tr[u].lans=max(tr[u].lans,tr[ls].lans+tr[rs].lans);
if(tr[rs].rans==(tr[rs].r-tr[rs].l+1)) tr[u].rans=max(tr[u].rans,tr[rs].rans+tr[ls].rans);
}
tr[u].l=tr[ls].l,tr[u].r=tr[rs].r;
tr[u].L=tr[ls].L,tr[u].R=tr[rs].R;
}
void modify(int u,int pos)//在当前管辖的区间更新某个位子.
{
int ls=(u<<1),rs=(u<<1|1);
if(pos>tr[u].r||pos<tr[u].l) return;
if(tr[u].l==tr[u].r&&tr[u].l==pos)
{
int odd=tr[u].L;
tr[u].L=tr[u].R=(!odd);
return;
}
modify(ls,pos);
modify(rs,pos);
push_up(u);
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u].l=tr[u].r=l;
tr[u].L=tr[u].R=0;
tr[u].lans=tr[u].rans=1;
tr[u].ans=1;return;
}int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
push_up(u);
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
build(1,1,n);
while(q--)
{
int x;
scanf("%d",&x);
modify(1,x);
printf("%d\n",tr[1].ans);
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+50;
struct Tree{
int l,r,mul,add,sum;//当前节点所管辖的左右区间,mul,add延迟标记,区间总和sum.
}tr[N<<2];
int n,m,p,w[N];
void push_down(int u)
{
tr[u<<1].sum=(tr[u].mul*tr[u<<1].sum+(tr[u].add*(tr[u<<1].r-tr[u<<1].l+1))%p)%p;
tr[u<<1|1].sum=(tr[u].mul*tr[u<<1|1].sum+(tr[u].add*(tr[u<<1|1].r-tr[u<<1|1].l+1))%p)%p;
tr[u<<1].mul=(tr[u<<1].mul*tr[u].mul)%p;
tr[u<<1|1].mul=(tr[u<<1|1].mul*tr[u].mul)%p;
tr[u<<1].add=(tr[u<<1].add*tr[u].mul+tr[u].add)%p;
tr[u<<1|1].add=(tr[u<<1|1].add*tr[u].mul+tr[u].add)%p;
tr[u].add=0,tr[u].mul=1;
}
void push_up(int u)
{
tr[u].l=tr[u<<1].l;tr[u].r=tr[u<<1|1].r;
tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%p;
}
void add(int u,int l,int r,int val)
{
if(r<tr[u].l||l>tr[u].r) return;
if(l<=tr[u].l&&tr[u].r<=r)
{
tr[u].add+=val;
tr[u].add%=p;
tr[u].sum=(tr[u].sum+val*(tr[u].r-tr[u].l+1))%p;
return;
}
push_down(u);
add(u<<1,l,r,val);
add(u<<1|1,l,r,val);
push_up(u);
}
void mul(int u,int l,int r,int val)
{
if(r<tr[u].l||l>tr[u].r) return;
if(l<=tr[u].l&&tr[u].r<=r)
{
tr[u].add*=val;
tr[u].add%=p;
tr[u].mul*=val;
tr[u].mul%=p;
tr[u].sum=(tr[u].sum*val)%p;
return;
}
push_down(u);
mul(u<<1,l,r,val);
mul(u<<1|1,l,r,val);
push_up(u);
}
void build(int u,int l,int r)
{
tr[u].mul=1;
if(l==r)
{
tr[u].l=tr[u].r=l;
tr[u].sum=w[l]%p;
return;
}int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
push_up(u);
}
int query(int u,int l,int r)
{
if(r<tr[u].l||l>tr[u].r) return 0;
if(l<=tr[u].l&&tr[u].r<=r)
{
return tr[u].sum%p;
}push_down(u);
return (query(u<<1,l,r)+query(u<<1|1,l,r))%p;
}
signed main()
{
scanf("%lld%lld%lld",&n,&m,&p);
for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
build(1,1,n);
while(m--)
{
int op,x,y,k;scanf("%lld",&op);
if(op==1)
{
scanf("%lld%lld%lld",&x,&y,&k);
mul(1,x,y,k);
}
else if(op==2)
{
scanf("%lld%lld%lld",&x,&y,&k);
add(1,x,y,k);
}
else
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",query(1,x,y));
}
}
}
下面那个和这个一样的...
P2023 [AHOI2009] 维护序列
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+50;
struct Tree{
int l,r,mul,add,sum;//当前节点所管辖的左右区间,mul,add延迟标记,区间总和sum.
}tr[N<<2];
int n,m,p,w[N];
void push_down(int u)
{
tr[u<<1].sum=(tr[u].mul*tr[u<<1].sum+(tr[u].add*(tr[u<<1].r-tr[u<<1].l+1))%p)%p;
tr[u<<1|1].sum=(tr[u].mul*tr[u<<1|1].sum+(tr[u].add*(tr[u<<1|1].r-tr[u<<1|1].l+1))%p)%p;
tr[u<<1].mul=(tr[u<<1].mul*tr[u].mul)%p;
tr[u<<1|1].mul=(tr[u<<1|1].mul*tr[u].mul)%p;
tr[u<<1].add=(tr[u<<1].add*tr[u].mul+tr[u].add)%p;
tr[u<<1|1].add=(tr[u<<1|1].add*tr[u].mul+tr[u].add)%p;
tr[u].add=0,tr[u].mul=1;
}
void push_up(int u)
{
tr[u].l=tr[u<<1].l;tr[u].r=tr[u<<1|1].r;
tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%p;
}
void add(int u,int l,int r,int val)
{
if(r<tr[u].l||l>tr[u].r) return;
if(l<=tr[u].l&&tr[u].r<=r)
{
tr[u].add+=val;
tr[u].add%=p;
tr[u].sum=(tr[u].sum+val*(tr[u].r-tr[u].l+1))%p;
return;
}
push_down(u);
add(u<<1,l,r,val);
add(u<<1|1,l,r,val);
push_up(u);
}
void mul(int u,int l,int r,int val)
{
if(r<tr[u].l||l>tr[u].r) return;
if(l<=tr[u].l&&tr[u].r<=r)
{
tr[u].add*=val;
tr[u].add%=p;
tr[u].mul*=val;
tr[u].mul%=p;
tr[u].sum=(tr[u].sum*val)%p;
return;
}
push_down(u);
mul(u<<1,l,r,val);
mul(u<<1|1,l,r,val);
push_up(u);
}
void build(int u,int l,int r)
{
tr[u].mul=1;
if(l==r)
{
tr[u].l=tr[u].r=l;
tr[u].sum=w[l]%p;
return;
}int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
push_up(u);
}
int query(int u,int l,int r)
{
if(r<tr[u].l||l>tr[u].r) return 0;
if(l<=tr[u].l&&tr[u].r<=r)
{
return tr[u].sum%p;
}push_down(u);
return (query(u<<1,l,r)+query(u<<1|1,l,r))%p;
}
signed main()
{
scanf("%lld%lld",&n,&p);
for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
build(1,1,n);
scanf("%lld",&m);
while(m--)
{
int op,x,y,k;scanf("%lld",&op);
if(op==1)
{
scanf("%lld%lld%lld",&x,&y,&k);
mul(1,x,y,k);
}
else if(op==2)
{
scanf("%lld%lld%lld",&x,&y,&k);
add(1,x,y,k);
}
else
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",query(1,x,y));
}
}
}
P1637 三元上升子序列
这题用树状数组更好写,我主要是练下线段树而已...中间还是出现了小小的bug,我不行i...
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e4+40;
int w[N];
int ls[N];
struct Tree{
int l,r,sum;
}tr[2][N<<2];//开两颗线段树维护前面有多少比它小的,后面有多少比它大的.
void build(int u,int l,int r,int op)
{
tr[op][u].sum=0;
tr[op][u].l=l,tr[op][u].r=r;
if(l==r) return;
int mid=(l+r)>>1;
build(u<<1,l,mid,op);
build(u<<1|1,mid+1,r,op);
}
void add(int u,int pos,int val,int op)//使得单点加上多少.
{
if(pos>tr[op][u].r||pos<tr[op][u].l) return;
if(pos==tr[op][u].l&&pos==tr[op][u].r)
{
tr[op][u].sum+=val;
return;
}
add(u<<1,pos,val,op);
add(u<<1|1,pos,val,op);
tr[op][u].sum=tr[op][u<<1].sum+tr[op][u<<1|1].sum;
}
int query(int u,int l,int r,int op)//查询区间答案.
{
if(l>tr[op][u].r||r<tr[op][u].l) return 0;
if(l<=tr[op][u].l&&r>=tr[op][u].r)
{
return tr[op][u].sum;
}return query(u<<1,l,r,op)+query(u<<1|1,l,r,op);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
ls[i]=w[i];
}sort(ls+1,ls+1+n);
build(1,1,n,0);
build(1,1,n,1);
for(int i=1;i<=n;i++)
{
w[i]=lower_bound(ls+1,ls+1+n,w[i])-ls;
add(1,w[i],1,1);
}
ll ans=0;
for(int i=1;i<=n;i++)
{
add(1,w[i],-1,1);
if(w[i]>1&&w[i]<n) ans+=1ll*query(1,1,w[i]-1,0)*query(1,w[i]+1,n,1);
add(1,w[i],1,0);
}printf("%lld\n",ans);
return 0;
}
CF915E Physical Education Lessons
动态开点.
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+5e6;
int lazy[N],ls[N],rs[N],sum[N],root,cnt;//线段树节点u的左右两个端点.以及这个端点的权值.
void pushdown(int u,int l,int r)
{
if(~lazy[u])
{
if(!ls[u]) ls[u]=++cnt;
if(!rs[u]) rs[u]=++cnt;
int mid=(l+r)>>1;
sum[ls[u]]=(mid-l+1)*lazy[u];
sum[rs[u]]=(r-mid)*lazy[u];
lazy[ls[u]]=lazy[rs[u]]=lazy[u];
lazy[u]=-1;
}
}
void modify(int &u,int l,int r,int L,int R,int val)
{
if(!u) u=++cnt;
if(L<=l&&r<=R)
{
sum[u]=val*(r-l+1);
lazy[u]=val;
return;
}int mid=(l+r)>>1;
pushdown(u,l,r);
if(L<=mid) modify(ls[u],l,mid,L,R,val);
if(R>mid) modify(rs[u],mid+1,r,L,R,val);
sum[u]=sum[ls[u]]+sum[rs[u]];
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
//我们假设工作日为0,非工作日为1.这样比较方便.
memset(lazy,-1,sizeof lazy);
modify(root,1,n,1,n,0);
while(q--)
{
int L,R,k;
scanf("%d%d%d",&L,&R,&k);
modify(root,1,n,L,R,2-k);//区间修改成2-k.
printf("%d\n",n-sum[1]);//输出答案.
}
return 0;
}
P3384 【模板】轻重链剖分
树链剖分.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+500;
ll n,m,r,p;
ll w[N];
vector<int>v[N];
ll dep[N],siz[N],dfn[N],f[N];
//跑出深度,子树大小,重儿子,父亲.
void dfs1(int u,int fa)
{
siz[u]=1;dep[u]=dep[fa]+1;f[u]=fa;
int num=v[u].size();
for(int i=0;i<num;i++)
{
int son=v[u][i];
if(son==fa) continue;
dfs1(son,u);
siz[u]+=siz[son];
if(siz[son]>siz[dfn[u]]) dfn[u]=son;
}
}
//跑出每个节点的下标以及处理它们的权值,然后统计重链的起点.
ll id=0,idx[N],top[N],val[N];
void dfs2(int u,int topf)
{
idx[u]=++id;
top[u]=topf;
val[id]=w[u];
if(!dfn[u]) return;
dfs2(dfn[u],topf);
int num=v[u].size();
for(int i=0;i<num;i++)
{
int son=v[u][i];
if(idx[son]) continue;
dfs2(son,son);
}
}
//写一份有线段树区间修改,区间求和功能的树.
struct Tree{
ll l,r,len,sum,lazy;
}tr[N<<2];
void pushup(int u)
{
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void pushdown(int u)
{
tr[u<<1].sum=(tr[u<<1].sum+tr[u].lazy*tr[u<<1].len%p)%p;
tr[u<<1|1].sum=(tr[u<<1|1].sum+tr[u].lazy*tr[u<<1|1].len%p)%p;
tr[u<<1].lazy=(tr[u<<1].lazy+tr[u].lazy)%p;
tr[u<<1|1].lazy=(tr[u<<1|1].lazy+tr[u].lazy)%p;
tr[u].lazy=0;
}
void build(int u,int l,int r)
{
tr[u].len=(r-l+1);tr[u].l=l;tr[u].r=r;
if(l==r)
{
tr[u].l=tr[u].r=l;
tr[u].sum=val[l];
return;
}int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void add(int u,int L,int R,int k)
{
if(tr[u].r<L||R<tr[u].l) return;
if(L<=tr[u].l&&tr[u].r<=R)
{
tr[u].sum=(tr[u].sum+k*(tr[u].len)%p)%p;
tr[u].lazy=(tr[u].lazy+k)%p;
return;
}pushdown(u);
add(u<<1,L,R,k);
add(u<<1|1,L,R,k);
pushup(u);
}
ll query(int u,int L,int R)
{
if(tr[u].r<L||R<tr[u].l) return 0;
if(L<=tr[u].l&&tr[u].r<=R) return tr[u].sum%p;
pushdown(u);
return (query(u<<1,L,R)+query(u<<1|1,L,R))%p;
}
//实现v->u的修改以及查询操作.
void Treeadd(int x,int y,int k)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
add(1,idx[top[x]],idx[x],k);
x=f[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
add(1,idx[x],idx[y],k);
}
ll Treesum(int x,int y)
{
ll ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=(ans+query(1,idx[top[x]],idx[x]))%p;
x=f[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans=(ans+query(1,idx[x],idx[y]))%p;
return ans;
}
int main()
{
scanf("%lld%lld%lld%lld",&n,&m,&r,&p);
for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs1(r,r);
dfs2(r,r);
build(1,1,n);
while(m--)
{
int op,x,y,z;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&x,&y,&z);
Treeadd(x,y,z%p);
}
else if(op==2)
{
scanf("%d%d",&x,&y);
printf("%lld\n",Treesum(x,y));
}
else if(op==3)
{
scanf("%d%d",&x,&z);
add(1,idx[x],idx[x]+siz[x]-1,z%p);
}
else
{
scanf("%d",&x);
printf("%lld\n",query(1,idx[x],idx[x]+siz[x]-1));
}
}
return 0;
}P1531 I Hate It
简单的单点修改和区间查询吧..
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+500;
struct Tree{
int l,r,ans;
}tr[N<<2];
int w[N];
void pushup(int u)
{
tr[u].ans=max(tr[u<<1].ans,tr[u<<1|1].ans);
}
void modify(int u,int l,int r,int val)
{
if(tr[u].r<l||tr[u].l>r) return;
if(l<=tr[u].l&&tr[u].r<=r)
{
tr[u].ans=max(tr[u].ans,val);
return;
}
modify(u<<1,l,r,val);
modify(u<<1|1,l,r,val);
pushup(u);
}
int query(int u,int l,int r)
{
if(tr[u].r<l||tr[u].l>r) return 0;
if(l<=tr[u].l&&tr[u].r<=r)
{
return tr[u].ans;
}return max(query(u<<1,l,r),query(u<<1|1,l,r));
}
void build(int u,int l,int r)
{
tr[u].l=l;tr[u].r=r;
if(l==r)
{
tr[u].ans=w[l];
return;
}int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
build(1,1,n);
while(m--)
{
char a;int b,c;
cin>>a>>b>>c;
if(a=='Q')
{
printf("%d\n",query(1,b,c));
}
else
{
modify(1,b,b,c);
}
}
return 0;
}P1276 校门外的树(增强版)
比模板还是多了些操作的...不错的题.
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
int ans1=0,ans2=0;
struct Tree{
int l,r,len,val;//1表示原来那颗大树,0表示没树苗,2表示有树苗,-1表示这个节点不能全部包括.
}tr[N<<2];
void cut(int u,int l,int r)
{
if(tr[u].l>r||tr[u].r<l) return;
if(tr[u].val!=-1) tr[u<<1].val=tr[u<<1|1].val=tr[u].val;
if(l<=tr[u].l&&tr[u].r<=r&&tr[u].val!=-1)
{
if(tr[u].val==1) tr[u].val=0;
if(tr[u].val==2)
{
ans1-=tr[u].len;
ans2+=tr[u].len;
tr[u].val=0;
}
return;
}
cut(u<<1,l,r);
cut(u<<1|1,l,r);
if(tr[u<<1].val!=tr[u<<1|1].val) tr[u].val=-1;
else tr[u].val=tr[u<<1].val;
}
void plant(int u,int l,int r)
{
if(tr[u].l>r||tr[u].r<l) return;
if(tr[u].val!=-1) tr[u<<1].val=tr[u<<1|1].val=tr[u].val;
if(l<=tr[u].l&&tr[u].r<=r&&tr[u].val!=-1)
{
if(tr[u].val==0) ans1+=tr[u].len,tr[u].val=2;
return;
}
plant(u<<1,l,r);
plant(u<<1|1,l,r);
if(tr[u<<1].val!=tr[u<<1|1].val) tr[u].val=-1;
else tr[u].val=tr[u<<1].val;
}
void build(int u,int l,int r)
{
tr[u].l=l,tr[u].r=r,tr[u].val=1,tr[u].len=(r-l+1);
if(l==r) return;
int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);n++;
build(1,1,n);
for(int i=1;i<=m;i++)
{
int a,b,c;scanf("%d%d%d",&a,&b,&c);
b++,c++;
if(a==0) cut(1,b,c);
else plant(1,b,c);
}printf("%d\n%d\n",ans1,ans2);//校门外留下的树苗数目 种上又被拔掉的树苗数目
return 0;
}P1438 无聊的数列
真的菜,区间修改的线段树还是可以打出bug?
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+500;
typedef long long ll;
ll a[N],w[N];
struct Tree{
ll l,r,len,sum,lazy;
}tr[N<<2];
void pushup(int u)
{
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void pushdown(int u)
{
tr[u<<1].lazy+=tr[u].lazy;
tr[u<<1|1].lazy+=tr[u].lazy;
tr[u<<1].sum+=tr[u].lazy*tr[u<<1].len;
tr[u<<1|1].sum+=tr[u].lazy*tr[u<<1|1].len;
tr[u].lazy=0;
}
void add(int u,int l,int r,int val)
{
if(l>tr[u].r||r<tr[u].l) return;
if(l<=tr[u].l&&tr[u].r<=r)
{
tr[u].lazy+=val;
tr[u].sum+=tr[u].len*val;
return;
}pushdown(u);
add(u<<1,l,r,val);
add(u<<1|1,l,r,val);
pushup(u);
}
ll query(int u,int l,int r)
{
if(l>tr[u].r||r<tr[u].l) return 0;
pushdown(u);
if(l<=tr[u].l&&tr[u].r<=r)
{
return tr[u].sum;
}
return query(u<<1,l,r)+query(u<<1|1,l,r);
}
void build(int u,int l,int r)
{
tr[u].l=l,tr[u].r=r,tr[u].len=r-l+1;
tr[u].lazy=0;
if(l==r)
{
tr[u].sum=w[l];
return;
}int mid=(r+l)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if(i==1) w[i]=a[i];
else w[i]=a[i]-a[i-1];
}build(1,1,n);
while(m--)
{
int op;int l,r,k,d;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d%d",&l,&r,&k,&d);
add(1,l,l,k);
add(1,l+1,r,d);
add(1,r+1,r+1,-(k+(r-l)*d));
}
else
{
int p;scanf("%d",&p);
printf("%lld\n",query(1,1,p));
}
}
return 0;
}P1471 方差
不难,但是也是值得学习的一题.
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+500;
struct Tree{
int l,r,len;
double sum;
double lazy;
}_tr[N<<2],__tr[N<<2];//一个维护区间和,另外一个维护区间平方和.
double w[N];
void pushup(int u)
{
_tr[u].sum=_tr[u<<1].sum+_tr[u<<1|1].sum;
__tr[u].sum=__tr[u<<1].sum+__tr[u<<1|1].sum;
}
void pushdown(int u)
{
__tr[u<<1].lazy+=__tr[u].lazy;
__tr[u<<1|1].lazy+=__tr[u].lazy;
__tr[u<<1].sum+=_tr[u<<1].sum*2*__tr[u].lazy+__tr[u<<1].len*__tr[u].lazy*__tr[u].lazy;
__tr[u<<1|1].sum+=_tr[u<<1|1].sum*2*__tr[u].lazy+__tr[u<<1|1].len*__tr[u].lazy*__tr[u].lazy;
_tr[u<<1].lazy+=_tr[u].lazy;
_tr[u<<1|1].lazy+=_tr[u].lazy;
_tr[u<<1].sum+=_tr[u].lazy*_tr[u<<1].len;
_tr[u<<1|1].sum+=_tr[u].lazy*_tr[u<<1|1].len;
_tr[u].lazy=__tr[u].lazy=0;
}
void add(int u,int l,int r,double val)
{
if(l>_tr[u].r||r<_tr[u].l) return;
if(_tr[u].l>=l&&_tr[u].r<=r)
{
__tr[u].lazy+=val;
__tr[u].sum+=_tr[u].sum*2*val+_tr[u].len*val*val;
_tr[u].lazy+=val;
_tr[u].sum+=val*_tr[u].len;
return;
}pushdown(u);
add(u<<1,l,r,val);
add(u<<1|1,l,r,val);
pushup(u);
}
double query(Tree tree[],int u,int l,int r)
{
if(l>tree[u].r||r<tree[u].l) return 0;
if(l<=tree[u].l&&tree[u].r<=r) return tree[u].sum;
pushdown(u);
return query(tree,u<<1,l,r)+query(tree,u<<1|1,l,r);
}
void build(int u,int l,int r)
{
_tr[u].l=l,_tr[u].r=r;
__tr[u].l=l,__tr[u].r=r;
_tr[u].len=__tr[u].len=(r-l+1);
_tr[u].lazy=__tr[u].lazy=0;
if(l==r)
{
_tr[u].sum=w[l];
__tr[u].sum=w[l]*w[l];
return;
}int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lf",&w[i]);
build(1,1,n);
int op,x,y;
double k;
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%lf",&x,&y,&k);
add(1,x,y,k);
}
else if(op==2)
{
scanf("%d%d",&x,&y);
printf("%.4f\n",query(_tr,1,x,y)/(y-x+1));
}
else
{
scanf("%d%d",&x,&y);
double age=query(_tr,1,x,y)/(y-x+1);
printf("%.4f\n",fabs(age*age-query(__tr,1,x,y)/(y-x+1)));
}
}
return 0;
}
京公网安备 11010502036488号