http://acm.hdu.edu.cn/showproblem.php?pid=6315
问了yxz后做的。。。
这个是我一般写线段树的方法,才觉得感觉有点麻烦,还是yxz的写法安逸些
#include"bits/stdc++.h"
#define out(x) cout<<#x<<"="<
using namespace std;
typedef long long LL;
const LL maxn=5e5+5;
int N,M;
int b[maxn];
struct AAA
{
int L,R,sum,lazy,Min;
};
AAA tree[maxn<<2];
void Build(int id,int L,int R)
{
tree[id].L=L,tree[id].R=R;
tree[id].lazy=tree[id].sum=0;
if(L==R)
{
tree[id].Min=b[L];
return ;
}
int mid=L+R>>1;
Build(id<<1,L,mid);
Build(id<<1|1,mid+1,R);
tree[id].Min=min(tree[id<<1].Min,tree[id<<1|1].Min);
}
void pushup(int id)
{
tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
tree[id].Min=min(tree[id<<1].Min,tree[id<<1|1].Min);
}
void pushdown(int id)
{
if(tree[id].lazy==0)return ;
tree[id<<1].Min-=tree[id].lazy;
tree[id<<1|1].Min-=tree[id].lazy;
tree[id<<1].lazy+=tree[id].lazy;
tree[id<<1|1].lazy+=tree[id].lazy;
tree[id].lazy=0;
}
void Add(int id,int l,int r,int v)
{
if(tree[id].L>=l&&tree[id].R<=r)
{
if(tree[id].Min>1)//如果最小值大于1,说明这一段区间里面还没有能够计算答案的,就只做个标记
{
tree[id].lazy+=v;
tree[id].Min-=v;
return ;
}
if(tree[id].L==tree[id].R)//不能计算答案的区间已经过滤掉了,现在只用计算每个答案了
{
tree[id].lazy+=v;
tree[id].sum=tree[id].lazy/b[tree[id].L];
tree[id].Min=b[tree[id].L]; //计算答案后又重新变回b[i]
return ;
}
}
pushdown(id);
int mid=tree[id].L+tree[id].R>>1;
if(r<=mid)Add(id<<1,l,r,v);
else if(l>mid)Add(id<<1|1,l,r,v);
else
{
Add(id<<1,l,mid,v);
Add(id<<1|1,mid+1,r,v);
}
pushup(id);
}
LL query(int id,int qL,int qR)
{
if(tree[id].L>=qL&&tree[id].R<=qR)return tree[id].sum;
int mid=tree[id].L+tree[id].R>>1;
pushdown(id);
if(qR<=mid)return query(id<<1,qL,qR);
else if(qL>mid)return query(id<<1|1,qL,qR);
else
{
return query(id<<1,qL,mid)+query(id<<1|1,mid+1,qR);
}
}
void print()//打印出线段树
{
for(int i=1;i<4*N;i++)
{
cout<<"id="<" Min=" <.Min<<" sum="<.sum<<" lazy="<.lazy<<" | ";
if((i&(i+1))==0)cout<int main()
{
while(cin>>N>>M)
{
for(int i=1;i<=N;i++)scanf("%d",&b[i]);
Build(1,1,N);
char cmd[10];
int L,R;
while(M--)
{
scanf("%s%d%d",cmd,&L,&R);
if(cmd[0]=='a')
{
Add(1,L,R,1);
}
else
{
printf("%d\n",query(1,L,R));
}
}
}
}
yxz的写法
#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const LL maxn=1e5+5;
int b[maxn];
int lazy[maxn<<2]; //用来记录对答案的贡献
int mi[maxn<<2],sum[maxn<<2];
int N,M;
void Build(int id,int L,int R)
{
sum[id]=0;
lazy[id]=0;
if(L==R)
{
mi[id]=b[L];
return ;
}
int mid=L+R>>1;
Build(id<<1,L,mid);
Build(id<<1|1,mid+1,R);
mi[id]=min(mi[id<<1],mi[id<<1|1]);
}
void pushdown(int id)
{
if(lazy[id]==0)return ;
lazy[id<<1]+=lazy[id];
lazy[id<<1|1]+=lazy[id];
mi[id<<1]-=lazy[id];
mi[id<<1|1]-=lazy[id];
lazy[id]=0;
}
void pushup(int id)
{
mi[id]=min(mi[id<<1],mi[id<<1|1]);
sum[id]=sum[id<<1]+sum[id<<1|1];
}
void Add(int id,int L,int R,int qL,int qR,int v)
{
// cout<<"di="<if (qL<=L&&qR>=R)
{
if(mi[id]>1) //如果落到了某个线段上,而最小值不满足条件,就直接加在lazy上面,不用继续往下加了
{
lazy[id]+=v;
mi[id]--;
return ;
}
if(L==R) //如果到了最底层,就计算答案
{
lazy[id]+=v;
sum[id]=lazy[id]/b[L];
mi[id]=b[L];
return ;
}
}
pushdown(id);
int mid=L+R>>1;
if(qL<=mid)Add(id<<1,L,mid,qL,qR,v);
if(qR>=mid+1)Add(id<<1|1,mid+1,R,qL,qR,v);
pushup(id);
}
int query(int id,int L,int R,int qL,int qR)
{
if(qL<=L&&qR>=R)return sum[id];
pushdown(id);
int mid=L+R>>1;
int res=0;
if(qL<=mid)res+=query(id<<1,L,mid,qL,qR);
if(qR>=mid+1)res+=query(id<<1|1,mid+1,R,qL,qR);
return res;
}
int main()
{
while(cin>>N>>M)
{
for(int i=1;i<=N;i++)scanf("%d",&b[i]);
char cmd[10];
int L,R;
Build(1,1,N);
for(int i=1;i<=M;i++)
{
scanf("%s%d%d",cmd,&L,&R);
if(cmd[0]=='a')
{
Add(1,1,N,L,R,1);
}
else
{
printf("%d\n",query(1,1,N,L,R));
}
}
}
}