真就一眼思路然后调了一天。
题意:一个数组,两种操作,第一种区间加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; }