Description
给定一个正整数序列A,要求支持以下操作:
1):ADD a b c 表示在[ab]上加上一个常数C
2):COVER a b c[ab]整体赋值为一个常数K
3):QUERY a b 查询[ab]sum

Input
第一行两个正整数nmn表示序列长度,m表示操作数。
第二行n个正整数,第i表示Ai的大小。
接下来的m行,每行有且仅有一种操作,具体和题目描述一致。
n,m<=100000,其他权值都<=50000,小心爆int。

Output
对于每个询问操作,输出答案。

Sample Input
10 10
17 18 16 12 13 7 13 6 11 20
QUERY 5 6
QUERY 2 7
ADD 1 6 13
QUERY 4 10
ADD 2 5 18
COVER 2 8 11
ADD 6 9 5
QUERY 8 8
ADD 6 9 18
QUERY 5 7

Sample Output
20
79
121
16
79

HINT

思路
记录3个标记:icoveri表示这个点是否在下传标记后被覆盖。coveri表示这个点被覆盖成了什么值。sumi表示这个点被增加了多少。下传时先考虑cover的下传,再考虑sum的下传。注意每次一个点被覆盖后这个点的sum值都要被赋成0

代码

#include <cstdio>

const int maxn=100000;

long long a[maxn+10];

struct segment_tree
{
  long long val[(maxn<<2)+10],sum[(maxn<<2)+10],cover[(maxn<<2)+10];
  int icover[(maxn<<2)+10];

  inline int updata(int now)//更新这个点的val
  {
    val[now]=val[now<<1]+val[now<<1|1];
    return val[now];
  }

  inline int pushdown(int now,int left,int right)//下传标记
  {
    int mid=(left+right)>>1;
    if(icover[now])//如果这个点被cover过,下传cover标记
      {
        icover[now]=0;
        cover[now<<1]=cover[now];
        sum[now<<1]=0;//注意sum标记要赋成0
        val[now<<1]=cover[now]*(mid-left+1);
        cover[now<<1|1]=cover[now];
        sum[now<<1|1]=0;
        val[now<<1|1]=cover[now]*(right-mid);
        icover[now<<1]=icover[now<<1|1]=1;//表示被覆盖过
      }
    sum[now<<1]+=sum[now];//下传sum标记
    val[now<<1]+=sum[now]*(mid-left+1);
    sum[now<<1|1]+=sum[now];
    val[now<<1|1]+=sum[now]*(right-mid);
    sum[now]=0;
    return 0;
  }

  int build(int now,int left,int right)//建树
  {
    if(left==right)
      {
        icover[now]=0;//初始化
        sum[now]=0;
        val[now]=a[left];
        return 0;
      }
    int mid=(left+right)>>1;
    build(now<<1,left,mid);
    build(now<<1|1,mid+1,right);
    updata(now);
    return 0;
  }

  int rcover(int now,int left,int right,int askl,int askr,long long cval)
  //将一个区间[left,right]cover成cval
  {
    if((askl<=left)&&(right<=askr))
      {
        icover[now]=1;//覆盖
        cover[now]=cval;
        sum[now]=0;//注意
        val[now]=cval*(right-left+1);
        return 0;
      }
    int mid=(left+right)>>1;
    pushdown(now,left,right);
    if(askl<=mid)
      {
        rcover(now<<1,left,mid,askl,askr,cval);
      }
    if(mid<askr)
      {
        rcover(now<<1|1,mid+1,right,askl,askr,cval);
      }
    updata(now);
    return 0;
  }

  int add(int now,int left,int right,int askl,int askr,long long cval)
  //将一个区间的值增加
  {
    if((askl<=left)&&(right<=askr))
      {
        sum[now]+=cval;
        val[now]+=cval*(right-left+1);
        return 0;
      }
    int mid=(left+right)>>1;
    pushdown(now,left,right);
    if(askl<=mid)
      {
        add(now<<1,left,mid,askl,askr,cval);
      }
    if(mid<askr)
      {
        add(now<<1|1,mid+1,right,askl,askr,cval);
      }
    updata(now);
    return 0;
  }

  long long getsum(int now,int left,int right,int askl,int askr)
  //求一段区间的和
  {
    if((askl<=left)&&(right<=askr))
      {
        return val[now];
      }
    int mid=(left+right)>>1;
    long long res=0;
    pushdown(now,left,right);
    if(askl<=mid)
      {
        res+=getsum(now<<1,left,mid,askl,askr);
      }
    if(mid<askr)
      {
        res+=getsum(now<<1|1,mid+1,right,askl,askr);
      }
    return res;
  }
};

segment_tree st;
int n,m,aa,b;
long long c;
char s[10];

int main()
{
  scanf("%d%d",&n,&m);
  for(register int i=1; i<=n; ++i)
    {
      scanf("%lld",&a[i]);
    }
  st.build(1,1,n);
  while(m--)
    {
      scanf("%s%d%d",s,&aa,&b);
      if(s[0]=='Q')
        {
          printf("%lld\n",st.getsum(1,1,n,aa,b));
        }
      else if(s[0]=='C')
        {
          scanf("%lld",&c);
          st.rcover(1,1,n,aa,b,c);
        }
      else
        {
          scanf("%lld",&c);
          st.add(1,1,n,aa,b,c);
        }
    }
  return 0;
}