队内训练5 线段树魔改
作者:互联网
队内训练5 线段树魔改
题目链接link.
真就一眼思路然后调了一天。
题意:一个数组,两种操作,第一种区间加v,第二种求区间内 ∑ i = l r ∑ j = i + 1 r a i ∗ a j \sum_{i=l}^r\sum_{j=i+1}^r{a_i*a_j} ∑i=lr∑j=i+1rai∗aj.
这个题,就,还行,线段树进阶吧属于是,但是思路还挺好出的。首先考虑维护两个值,一个sum一个value,两个值一起更新。当两个线段合并的时候,我们可以轻易推出:
v a l u e = v a l u e 1 + v a l u e 2 + s u m 1 ∗ s u m 2 value=value1+value2+sum1*sum2 value=value1+value2+sum1∗sum2.
当然啦这只是合并的时候的式子,我们还需要考虑懒标记下放更新的时候怎么更新。
易知,当一个区间同时加上w时,更新的方式应该是:
v a l u e + = ( w 2 ∗ l e n ∗ ( l e n − 1 ) / 2 + w ∗ ( l e n − 1 ) ∗ s u m ) value+=(w^2*len*(len-1)/2+w*(len-1)*sum) value+=(w2∗len∗(len−1)/2+w∗(len−1)∗sum).
然后改一改线段树就好啦。
说一下wa一天的原因吧。
第一个wa的点是,我的 lazy_tag 初始化的值是-1,后面update的时候,直接+=w,显然很傻逼的错误,不知道怎么的误打误撞过了样例,可能对线段树过于自信也没有再手造数据疯狂改取模和全局int128,最后还是池池找出来错哪了。呜呜。
第二个wa的点,就是,可以说是奇闻共赏了:
笑拉了家人们。看看我的return 0,最离谱的是,我对拍的时候,为了方便自己找错误,直接设置了t=1,对拍跑了一年跑不出差异。笑死。
AC代码:
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int mod=1e9+7;
int n;
struct qaq
{
int l,r;
int value=0;
int sum=0;
int lazy_tag=0;
}tree[400100];
int a[100100];
void build(int x,int l,int r)
{
tree[x].l=l;
tree[x].r=r;
tree[x].lazy_tag=0;
if(l==r)
{
tree[x].value=0;
tree[x].sum=a[l];
return ;
}
int mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
tree[x].value=tree[x*2].value+tree[x*2+1].value+tree[x*2].sum*tree[x*2+1].sum;
tree[x].sum%=mod;
tree[x].value%=mod;
}
void update(int x,int w)
{
int len=tree[x].r-tree[x].l+1;
tree[x].value += ( (((w*w)%mod)*((len*(len-1)/2)%mod)+(((w*(len-1))%mod)*tree[x].sum)%mod)%mod );
tree[x].sum += len*w;tree[x].sum%=mod;
tree[x].lazy_tag+=w;tree[x].lazy_tag%=mod;
return ;
}
void push_down(int x)
{
update(x*2,tree[x].lazy_tag);
update(x*2+1,tree[x].lazy_tag);
tree[x].lazy_tag=0;
}
void push_up(int x)
{
tree[x].sum=(tree[x*2].sum+tree[x*2+1].sum)%mod;
tree[x].value=((tree[x*2].value+tree[x*2+1].value)%mod+((tree[x*2].sum*tree[x*2+1].sum)%mod)%mod)%mod;
}
void change(int x,int l,int r,int w)
{
if(tree[x].l==l&&tree[x].r==r)
{
update(x,w);
return ;
}
if(tree[x].lazy_tag!=-1) push_down(x);
int mid=(tree[x].l+tree[x].r)/2;
if(r<=mid) change(x*2,l,r,w);
else if(l>=mid+1) change(x*2+1,l,r,w);
else
{
change(x*2,l,mid,w);
change(x*2+1,mid+1,r,w);
}
push_up(x);
}
pair<int,int> query(int x,int l,int r)
{
if(tree[x].l==l&&tree[x].r==r)
{
return make_pair(tree[x].value,tree[x].sum);
}
if(tree[x].lazy_tag!=0) push_down(x);
int mid=(tree[x].l+tree[x].r)/2;
if(r<=mid)
{
return query(x*2,l,r);
}
else if(l>=mid+1)
{
return query(x*2+1,l,r);
}
else
{
pair<int,int> oxy=query(x*2,l,mid);
pair<int,int> orz=query(x*2+1,mid+1,r);
return make_pair
( (oxy.first+orz.first+(oxy.second*orz.second)%mod)%mod,(oxy.second+orz.second)%mod );
}
}
signed main( )
{
int t;
scanf("%lld",&t);
while(t--)
{
int q;
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
while(q--)
{
int op,l,r;
scanf("%lld%lld%lld",&op,&l,&r);
if(op==1)//区间修改
{
int v;
scanf("%lld",&v);
change(1,l,r,v);
}
else if(op==2)//区间查询
{
int ans=query(1,l,r).first;
ans=(ans%mod+mod)%mod;
printf("%lld\n",ans);
}
}
}
return 0;
}
标签:int,线段,tree,mid,value,树魔改,队内,sum,mod 来源: https://blog.csdn.net/weixin_47523602/article/details/120319347