在文章的 开头 当然是贴一个我自己写的 裸码 (毋庸置疑的是 T了三个点的)(手动猥琐)
T了#2 #9#10
#include<iostream>
using namespace std;
int a[100010];
int n,m,x,y,z;
struct ac
{
int l,r,sum;
}tree[500010];
void build(int d,int l,int r)
{
tree[d].l=l;
tree[d].r=r;
if(l==r)
{
tree[d].sum=a[l];
return ;
}
build(d*2,l,(l+r)/2);
build(d*2+1,(l+r)/2+1,r);
tree[d].sum=tree[d*2].sum+tree[d*2+1].sum;
}
/*void add(int node,int l,int r,int xx)
{
if(l==r)
{
a[l]+=xx;
return ;
}
int mid=(tree[node].l+tree[node].r)/2;
if(l<=mid)add(node*2,l,r,xx);
else add(node*2+1,l,r,xx);
tree[node].sum=tree[2*node].sum+tree[2*node+1].sum;
}*/
int find(int d,int l,int r)
{
if(tree[d].l==l&&tree[d].r==r)
{
return tree[d].sum;
}
int mid=(tree[d].l+tree[d].r)/2;
if(r<=mid)
{
return find(d*2,l,r);
}
if(l>mid)
{
return find(d*2+1,l,r);
}
if(r>mid&&l<=mid)
{
return find(d*2,l,mid)+find(d*2+1,mid+1,r);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
build(1,1,n);
for(int i=1;i<=m;i++)
{
cin>>x;
if(x==1)
{
cin>>x>>y>>z;
for(int i=x;i<=y;i++)
{
a[i]+=z;
}
build(1,1,n);
}
else
{
cin>>y>>z;
cout<<find(1,y,z)<<endl;
}
}
return 0;
}
然而 还有 T了 8 9 10三个点的
#include<iostream>
#include<cstdio>
using namespace std;
long long a[100010];
long long n,m,x,y,z;
struct ac
{
long long l,r,sum;
}tree[500010];
void build(long long d,long long l,long long r)
{
tree[d].l=l;
tree[d].r=r;
if(l==r)
{
tree[d].sum=a[l];
return ;
}
build(d*2,l,(l+r)/2);
build(d*2+1,(l+r)/2+1,r);
tree[d].sum=tree[d*2].sum+tree[d*2+1].sum;
}
/*void add(int node,int l,int r,int xx)
{
if(l==r)
{
a[l]+=xx;
return ;
}
int mid=(tree[node].l+tree[node].r)/2;
if(l<=mid)add(node*2,l,r,xx);
else add(node*2+1,l,r,xx);
tree[node].sum=tree[2*node].sum+tree[2*node+1].sum;
}*/
int find(long long d,long long l,long long r)
{
if(tree[d].l==l&&tree[d].r==r)
{
return tree[d].sum;
}
long long mid=(tree[d].l+tree[d].r)/2;
if(r<=mid)
{
return find(d*2,l,r);
}
if(l>mid)
{
return find(d*2+1,l,r);
}
if(r>mid&&l<=mid)
{
return find(d*2,l,mid)+find(d*2+1,mid+1,r);
}
}
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
build(1,1,n);
for(int i=1;i<=m;i++)
{
cin>>x;
if(x==1)
{
scanf("%lld%lld%lld",&x,&y,&z);
for(int i=x;i<=y;i++)
{
a[i]+=z;
}
build(1,1,n);
}
else
{
scanf("%lld%lld",&y,&z);
cout<<find(1,y,z)<<endl;
}
}
return 0;
}
关于这比较玄学的问题 …………
在文章的最后 当然还是 贴上 标记下传的AC代码啦
//针对某些评测机 长整型 要用lld 而不能用I64d 否则会全T
#include <cstdio>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define Maxn 500000
#define ll long long
using namespace std;
ll seg[Maxn];
ll mark[Maxn];
//**在子函数中调用的函数 要在声明这个子函数前声明子函数中出现的子函数;
//前提是 子函数位于主函数之上的情况**
void pushup(ll rt)//同下
{
seg[rt]=seg[rt<<1]+seg[rt<<1|1];//已知rt两个字区间的和 求rt的区间和
}
void build(ll rt,ll l,ll r)//建树
{
if (l==r)
scanf("%lld",&seg[rt]);//具体到某个点上 区间中只有这一个点
else
{
ll mid=(l+r)/2;//二分 把大区间分成左右两个小区间
build(lson);//左区间 lson即 rt*2,l,mid;
build(rson);//右区间 rson即 rt*2+1,mid+1,r;
pushup(rt);//进行这一步就说明 区间中的点的个数不是一
//把左右区间的和加起来就是这个父亲区间的和
}
}
void pushdown(ll rt,ll x)//下传
{
if (mark[rt])//相当于 世传的lazy大法 ///如果rt这个区间被标记了 就下传
{
mark[rt<<1]+=mark[rt];//神奇的位运算 既然父亲区间被标记了
mark[rt<<1|1]+=mark[rt];//那么 其子区间不可避免的被标记
seg[rt<<1]+=mark[rt]*(x-x/2);//由于 标记的是整个区间
seg[rt<<1|1]+=mark[rt]*(x/2);//累加起来就是 区间原和+区间长度*增幅
mark[rt]=0;//清空标记
}
}
ll query(ll rt,ll l,ll r,ll L,ll R)
{
if (l>=L && r<=R)
return seg[rt];
else
{
pushdown(rt,r-l+1);
ll mid=(r+l)/2,ans=0;
if (mid>=L)
ans+=query(lson,L,R);
if (mid<R)
ans+=query(rson,L,R);
return ans;
}
}
void update(ll rt,ll l,ll r,ll L,ll R,ll x)
{
if (l>=L && r<=R)//判断 rt是否被更新的区间包含
seg[rt]+=(r-l+1)*x,mark[rt]+=x;
else
{
pushdown(rt,r-l+1);//如果没有被包含 先把之前的标记 清空
ll mid=(r+l)/2;
if (mid>=L)//判断rt的lson与被更新的有没有交集
update(lson,L,R,x);
if (mid<R)//判断rt的rson与被更新的有没有交集
update(rson,L,R,x);
pushup(rt);//到这一步 rt的左右两个子区间的和已经被更新
//可以放心大胆的进行求和
//不可小瞧递归的魅力
}
}
main()//现在才知道主函数类型可以省略
{
ll n,m;
int s;
ll x,y,z;
scanf("%lld%lld",&n,&m);
build(1,1,n);
while(m--)
{
scanf("%d",&s);//scanf数字记得要有 地址符& 字符串就不用
if(s == 1)
{
scanf("%lld%lld%lld",&x,&y,&z);
update(1,1,n,x,y,z);
}
else
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",query(1,1,n,x,y));
}
}
}