Pku3468 A Simple Problem with Integers

You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of op
eration is to add some given number to each number in a given interval. The other is to ask for the
sum of numbers in a given interval.
1.给[a ,b]整体上加上一个常数c。
2.查询[a ,b]区间的和。
Input
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.
Output
You need to answer all Q commands in order. One answer in a line. The sums may exceed the range of 32-bit integers
Sample Input
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
Sample Output
4
55
9
15

Sol1:Lazy标记

#include
#define mid (s[x].l+s[x].r>>1)
int n,m,d[100001];
char p[3];
struct oo{int l,r;long long lazy,sum;}s[400001];
void build(int x,int l,int r)
{
    s[x].l=l,s[x].r=r;
    if(l==r){s[x].sum=d[l];return ;}
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    s[x].sum=s[x<<1].sum+s[x<<1|1].sum;
}
void pushdown(int x)  //lazy标记下传
{
    int l=x<<1,r=x<<1|1;
    s[l].sum+=(s[l].r-s[l].l+1)*s[x].lazy;
    s[r].sum+=(s[r].r-s[r].l+1)*s[x].lazy;
    s[l].lazy+=s[x].lazy;s[r].lazy+=s[x].lazy;
    s[x].lazy=0;
}
void change(int x,int l,int r,int v)
{
    if(l<=s[x].l&&r>=s[x].r)
    {
        s[x].sum+=(s[x].r-s[x].l+1)*v;
        s[x].lazy+=v;
        return ;
    }
    if(s[x].lazy)  //记得标记下传
        pushdown(x);
    if(l<=mid)
        change(x<<1,l,r,v);
    if(r>mid)
        change(x<<1|1,l,r,v);
    s[x].sum=s[x<<1].sum+s[x<<1|1].sum;
}
long long get(int x,int l,int r)
{
    if(l<=s[x].l&&r>=s[x].r)
        return s[x].sum;
    if(s[x].lazy)       //记得标记下传
       pushdown(x);
    long long ans=0;
    if(l<=mid)ans+=get(x<<1,l,r);
    if(r>mid)ans+=get(x<<1|1,l,r);
    s[x].sum=s[x<<1].sum+s[x<<1|1].sum;
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&d[i]);
    build(1,1,n);int x,y,z;
    while(m--)
    {
        scanf("%s",p+1);
        if(p[1]=='Q')
        {
            scanf("%d%d",&x,&y);
            printf("%lld\n",get(1,x,y));
        }
        else
        {
            scanf("%d%d%d",&x,&y,&z);
            change(1,x,y,z);
        }
    }
}

  

所谓标记永久化就是不下传标记,让标记永远都待在当前节点上。

对于修改操作,假如我们要修改[l,r],那么我们要把所有包含[l,r]的区间统计的信息都更改为受到标记影响后的,对于所有被[l,r]包含的第一级区间(就是递归时被包含不细分下去)我们就打上标记,更新信息。

为什么要一路修改下来而不是像普通线段树那样一路updata上去呢?因为假如用updata的话,有可能会被明明被标记影响了,但是由于不是第一级区间所以没有对它进行更改的结点向上更新出错误的信息。

对于询问,我们只需要把从根到我们要询问的区间这一路上所有的标记影响全部累加起来,统计答案再加上去即可。这样子,对于所有的区间,覆盖它的标记都逃不掉。

下面这个代码是Pku3468 A Simple Problem with Integers

#include
#include
#include
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 201000
using namespace std;
int n,m;char p[3];
long long sum[N*4],add[N*4];
int a[N];
void build(int l,int r,int rt)
{
    if(l==r)
	{
        sum[rt]=a[l];return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int rt,int l,int r,int v,int xl,int xr)
{
    sum[rt]+=v*(min(xr,r)-max(xl,l)+1);
    if(l>=xl&&r<=xr) //等到区间完全重合时,再给add加上v增加的标记 
	{
        add[rt]+=v; 
		return;
    }
    int mid=(l+r)>>1;
    if(xr<=mid)  
	   update(rt<<1,l,mid,v,xl,xr);
    else
	{
        if(xl>mid)   
		   update(rt<<1|1,mid+1,r,v,xl,xr);
        else 
		   update(rt<<1,l,mid,v,xl,xr),update(rt<<1|1,mid+1,r,v,xl,xr);
		  
    }
}
long long query(int rt,int ad,int l,int r,int xl,int xr)
{
    if(xl<=l&&xr>=r)
	{
        return sum[rt]+ad*(min(xr,r)-max(xl,l)+1);
    }  
    int mid=(l+r)>>1;
    if(xr<=mid) 
	   return query(rt<<1,ad+add[rt],l,mid,xl,xr);
    else
	{
     if(xl>mid) 
	  return query(rt<<1|1,ad+add[rt],mid+1,r,xl,xr);
     else 
		return query(rt<<1,ad+add[rt],l,mid,xl,xr)+query(rt<<1|1,ad+add[rt],mid+1,r,xl,xr);
    }
}
int main(){
    scanf("%d%d",&n,&m);
    pos(i,1,n) scanf("%d",&a[i]);
    build(1,n,1);
    pos(i,1,m)
	{
        scanf("%s",p+1);
        int x,y;scanf("%d%d",&x,&y);
        if(p[1]=='C')
		{
            int k;scanf("%d",&k);
            update(1,1,n,k,x,y);
        }
        else printf("%lld\n",query(1,0,1,n,x,y));
    }
    return 0;
}

  下面这个代码是xyh的

#include 
#include 
using namespace std;
typedef long long ll;
 
const int maxn=1e5+5;
 
int n,m;
ll a[maxn];
 
struct segment_tree 
{
    ll sum[maxn<<2],add[maxn<<2];
    void updata(int p) 
	{
        sum[p]=sum[p<<1]+sum[p<<1|1];
    }
    void build(int p,int l,int r) 
	{
        if(l==r) {sum[p]=a[l];return;}
        int mid=(l+r)>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        updata(p);
    }
    void change(int p,int l,int r,int L,int R,ll v) 
	{
        sum[p]+=v*(R-L+1);
        if(L<=l&&r<=R) 
		{
			 add[p]+=v;
			 return;
		}
        int mid=(l+r)>>1;
        if(R<=mid)
		   change(p<<1,l,mid,L,R,v);
        else 
		    if(L>mid)
			   change(p<<1|1,mid+1,r,L,R,v);
            else 
			  change(p<<1,l,mid,L,mid,v),change(p<<1|1,mid+1,r,mid+1,R,v);
    }
 
    ll query(int p,int l,int r,int L,int R) 
	{
        if(L<=l&&r<=R)
		   return sum[p];
        int mid=(l+r)>>1;
		ll res=add[p]*(R-L+1);
        if(R<=mid)
		   res+=query(p<<1,l,mid,L,R);
        else 
		   if(L>mid)
		      res+=query(p<<1|1,mid+1,r,L,R);
           else 
		    res+=query(p<<1,l,mid,L,mid)+query(p<<1|1,mid+1,r,mid+1,R);
        return res;
    }
}T;
 
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lld",a+i);
    T.build(1,1,n);
    for(int i=1;i<=m;i++) {
        int opt,l,r;ll v;
        char p[3];
      
        scanf("%s",p+1);
        int x,y;scanf("%d%d",&l,&r);
        if(p[1]=='C')
		{
            scanf("%lld",&v);
            T.change(1,1,n,l,r,v);
        }
        else printf("%lld\n",T.query(1,1,n,l,r));
    }
    return 0;
}

  

 

  

你可能感兴趣的:(Pku3468 A Simple Problem with Integers)