https://ac.nowcoder.com/acm/contest/19684/D
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
long long A[MAXN];
struct tnode
{//sum[0] l,r 区间和
//sum[1] l,r区间平方和
//lazy[0] 区间乘积懒标记
//lazy[1] 区间加法 懒标记
long long sum[2], lazy[2];
int l, r;
};
struct Segment_Tree
{
tnode t[4 * MAXN];
void init_lazy(int root)
{
t[root].lazy[0] = 1;//a 乘数
t[root].lazy[1] = 0;//b 加数
}
void union_lazy(int fa, int ch)
{//y=ax+b
long long temp[2];
//a=a1(父亲)*a2 乘法
//b=a1(父亲)*b2+b1(父亲) 加法
temp[0] = t[fa].lazy[0] * t[ch].lazy[0];
temp[1] = t[fa].lazy[0] * t[ch].lazy[1] + t[fa].lazy[1];
t[ch].lazy[0] = temp[0];
t[ch].lazy[1] = temp[1];
}
void cal_lazy(int root)
{//该点的区间各个数的平方和 a*a*sum(a*a)(更新前区间平方和)+b*b*(r-l+1)+2*a*b*sum(区间和)
t[root].sum[1] = t[root].lazy[0] * t[root].lazy[0] * t[root].sum[1] +
t[root].lazy[1] * t[root].lazy[1] * (t[root].r - t[root].l + 1) +
t[root].lazy[0] * t[root].lazy[1] * 2 * t[root].sum[0];
// 该结点区间和 a*sum+(r-l+1)*b
t[root].sum[0] = t[root].lazy[0] * t[root].sum[0] +
t[root].lazy[1] * (t[root].r - t[root].l + 1);
return;
}
void push_down(int root)
{ //该节点的 加法 乘法
if (t[root].lazy[0] != 1 || t[root].lazy[1] != 0)
{
cal_lazy(root);//更新该结点数据
if (t[root].l != t[root].r)
{
int ch = root << 1;
union_lazy(root, ch);//更新左子树的 乘法 加法
union_lazy(root, ch + 1);
}
init_lazy(root);//初始化 该节点
}
}
void update (int root)
{
int ch = root << 1;
push_down(ch);
push_down(ch + 1);
//该结点的区间和
t[root].sum[0] = t[ch].sum[0] + t[ch + 1].sum[0];
//该点的区间平方和
t[root].sum[1] = t[ch].sum[1] + t[ch + 1].sum[1];
}
void build(int root, int l, int r)
{
t[root].l = l;
t[root].r = r;
init_lazy(root);//初始化树
if (l != r)
{
int mid = (l + r) >> 1;//左右树区间断点
int ch = root << 1;//树节点
build(ch, l, mid);//左树
build(ch + 1, mid + 1, r);//右树
update(root);//该结点的数据
}
else
{ //递归到尽头
//该点区间和
t[root].sum[0] = A[l];
//该点区间平方和
t[root].sum[1] = A[l] * A[l];
}
}
void change(int root, int l, int r, long long delta, int op)
{
push_down(root);//更新该结点,,已经初始化了
if (l == t[root].l && r == t[root].r)
{
t[root].lazy[op] = delta;
return;
}
int mid = (t[root].l + t[root].r) >> 1;
int ch = root << 1;
if (r <= mid)change(ch, l, r, delta,op);
else if (l > mid)change(ch + 1, l, r, delta,op);
else {change(ch, l, mid, delta,op); change(ch + 1, mid + 1, r, delta,op);}
update(root);
}
long long sum(int root, int l, int r, int op)
{
push_down(root);
if (t[root].l == l && t[root].r == r)
{
return t[root].sum[op];
}
int mid = (t[root].l + t[root].r) >> 1;
int ch = root << 1;
if (r <= mid)return sum(ch, l, r, op);
else if (l > mid)return sum(ch + 1, l, r, op);
else return sum(ch, l, mid, op) + sum(ch + 1, mid + 1, r, op);
}
};
Segment_Tree ST;
int n, m, op, l, r;
long long x;
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
{
scanf("%lld", &A[i]);
}
ST.build(1, 1, n);//建树
for (int _ = 1; _ <= m; ++_)
{
scanf("%d %d %d", &op, &l, &r);
if (op >= 3)
{
scanf("%lld", &x);
ST.change(1, l, r, x, op - 3);
}
else
{
printf("%lld\n", ST.sum(1, l, r, op-1));
}
}
return 0;
}
https://www.luogu.com.cn/problem/P3870
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000001;
int ans,n,m,a,b,c;
struct tree
{
int l,r,sum,add;
}t[maxn];
inline void build(int u,int x,int y)
{
t[u].l=x;
t[u].r=y;
if(x==y)
{
t[u].sum=0;//题目说每个灯都是关着的。
return ;
}
int mid=(x+y)>>1;
build(u*2,x,mid);build(u*2+1,mid+1,y);
}//建树不需要过多解释吧?
inline void tag(int u)
{
if(t[u].add==0)return;//如果这个父亲不需要更改还需要儿子什么事情呢?
//如果看不懂这句的话,一定要耐心往下看。
t[u*2].sum=t[u*2].r-t[u*2].l+1-t[u*2].sum;
t[u*2+1].sum=t[u*2+1].r-t[u*2+1].l+1-t[u*2+1].sum;//维护儿子的sum值。
if(t[u*2].add==0)//如果左儿子没有懒标记的话
t[u*2].add=1;//那么他现在有了懒标记,
//也就是它现在需要修改区间内的值了。
else t[u*2].add=0;//如果有懒标记的话,那么它现在不用动了
//因为这个做儿子连着被修改了两次,
//根据题意这个区间内的灯被开了一次,又被关了一次,
//是不是相当于最初的形态?
if(t[u*2+1].add==0)
t[u*2+1].add=1;
else t[u*2+1].add=0;//这个是处理右儿子的,解释同上。
t[u].add=0;//注意进行这部的时候
//左右儿子的父亲已经被修改过了
//所以父亲的懒标记要归0,也就是说父亲现在不需要更改。
}
inline void change(int u,int l,int r)
{
if(l<=t[u].l&&t[u].r<=r)
{
t[u].sum=t[u].r-t[u].l+1-t[u].sum;
if(t[u].add==0)
t[u].add=1;
else
t[u].add=0;
return ;//这个地方跟上面解释相同。
}
tag(u);
//此时,区间没有覆盖父亲,那么检查一下这个父亲用改不用
//如果父亲用改的话,那么由于我们之后需要用到它的儿子
//并且我们要改的区间没有覆盖父亲,所以现在要修改儿子了。
int mid=(t[u].l+t[u].r)>>1;
if(l<=mid)change(u*2,l,r);
if(r>mid)change(u*2+1,l,r);
//此处一定是a<=mid,b>mid这个仔细想想吧。
t[u].sum=t[u*2].sum+t[u*2+1].sum;
}
inline int ask(int u,int l,int r)
{
if(l<=t[u].l&&r>=t[u].r)return t[u].sum;
tag(u);
int mid=(t[u].l+t[u].r)/2;
int ans=0;
if(a<=mid)ans+=ask(u*2,l,r);
if(b>mid)ans+=ask(u*2+1,l,r);
return ans;
}//这个地方是板子。
int main()
{
cin>>n>>m;
build(1,1,n);
for(int i=1;i<=m;i++)
{
cin>>c>>a>>b;
if(c==0)
change(1,a,b);
else
cout<<ask(1,a,b)<<endl;
}
return 0;
}//完美结束。