用线段树对每种长度的区间维护权值和。

  考虑区间[l,r]+1对长度为k的区间的贡献,显然其为Σk-max(0,k-i)-max(0,k-(n-i+1)) (i=l~r)。

  大力展开讨论。首先变成Σk-Σmax(0,k-i)-Σmax(0,k-(n-i+1)) (i=l~r)。

  第一部分是一个常数,线段树上是加了一个等差数列。打上标记即可。

  后面两部分本质相同,现考虑Σmax(0,k-i) (i=l~r)。去掉max,即Σk-i (i=l~min(r,k))。根据r和k的大小关系讨论。若r<=k,线段树上加了一个一次函数;若r>k,线段树上加了一个二次函数。三种标记即可。

  常数巨大,下传标记时判一下是否有标记需要传可以快至少一倍。读入序列直接当做修改就能跑过。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 200010
#define P 1000000007
#define inv 500000004
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,m,a[N],s[][N];
struct data{int l,r,sum,lazy[];
}tree[N<<];
inline void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
inline void up(int k){tree[k].sum=tree[k<<].sum+tree[k<<|].sum;if (tree[k].sum>=P) tree[k].sum-=P;}
inline void update(int k,int x,int op)
{
inc(tree[k].sum,1ll*x*(s[op][tree[k].r]-s[op][tree[k].l-]+P)%P);
inc(tree[k].lazy[op],x);
}
inline void down(int k,int i)
{
update(k<<,tree[k].lazy[i],i),
update(k<<|,tree[k].lazy[i],i),
tree[k].lazy[i]=;
}
void build(int k,int l,int r)
{
tree[k].l=l,tree[k].r=r;
if (l==r) return;
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
}
void add(int k,int l,int r,int x,int op)
{
if (l>r) return;
if (tree[k].l==l&&tree[k].r==r) {update(k,x,op);return;}
if (tree[k].lazy[]) down(k,);
if (tree[k].lazy[]) down(k,);
if (tree[k].lazy[]) down(k,);
int mid=tree[k].l+tree[k].r>>;
if (r<=mid) add(k<<,l,r,x,op);
else if (l>mid) add(k<<|,l,r,x,op);
else add(k<<,l,mid,x,op),add(k<<|,mid+,r,x,op);
up(k);
}
int query(int k,int l,int r)
{
if (tree[k].l==l&&tree[k].r==r) return tree[k].sum;
if (tree[k].lazy[]) down(k,);
if (tree[k].lazy[]) down(k,);
if (tree[k].lazy[]) down(k,);
int mid=tree[k].l+tree[k].r>>;
if (r<=mid) return query(k<<,l,r);
else if (l>mid) return query(k<<|,l,r);
else return (query(k<<,l,mid)+query(k<<|,mid+,r))%P;
}
void modify(int l,int r,int x)
{
add(,r,n,1ll*(r-l+)*x%P,),add(,r,n,P-1ll*(s[][r]-s[][l-]+P)*x%P,);
add(,l,r-,1ll*x*inv%P,),add(,l,r-,1ll*x*(P+-l-inv)%P,),add(,l,r-,1ll*l*(l-)%P*inv%P*x%P,);
}
void change(int l,int r,int x)
{
add(,,n,1ll*(r-l+)*x%P,);
modify(l,r,P-x),modify(n-r+,n-l+,P-x);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj5291.in","r",stdin);
freopen("bzoj5291.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();
build(,,n);
for (int i=;i<=n;i++) s[][i]=s[][i-]+,s[][i]=(s[][i-]+i)%P,s[][i]=(s[][i-]+1ll*i*i)%P;
for (int i=;i<=n;i++) change(i,i,read());
while (m--)
{
int op=read();
if (op==)
{
int l=read(),r=read(),x=read();
if (l>r) swap(l,r);
change(l,r,x);
}
else
{
int l=read(),r=read();
printf("%d\n",query(,l,r));
}
}
return ;
}

BZOJ5291 BJOI2018链上二次求和(线段树)的更多相关文章

  1. [BZOJ5291][BJOI2018]链上二次求和(线段树)

    感觉自己做的麻烦了,但常数似乎不算差.(只是Luogu最慢的点不到2s本地要跑10+s) 感觉我的想法是最自然的,但不明白为什么网上似乎找不到这种做法.(不过当然所有的做法都是分类大讨论,而我的方法手 ...

  2. BZOJ5291/洛谷P4458/LOJ#2512 [Bjoi2018]链上二次求和 线段树

    原文链接http://www.cnblogs.com/zhouzhendong/p/9031130.html 题目传送门 - LOJ#2512 题目传送门 - 洛谷P4458 题目传送门 - BZOJ ...

  3. 2018.01.04 bzoj5291: [Bjoi2018]链上二次求和(线段树)

    传送门 线段树基础题. 题意:给出一个序列,要求支持区间加,查询序列中所有满足区间长度在[L,R][L,R][L,R]之间的区间的权值之和(区间的权值即区间内所有数的和). 想题555分钟,写题202 ...

  4. 【BZOJ5291】[BJOI2018]链上二次求和(线段树)

    [BZOJ5291][BJOI2018]链上二次求和(线段树) 题面 BZOJ 洛谷 题解 考虑一次询问\([l,r]\)的答案.其中\(S\)表示前缀和 \(\displaystyle \sum_{ ...

  5. bzoj 5291: [Bjoi2018]链上二次求和

    Description 有一条长度为n的链(1≤i<n,点i与点i+1之间有一条边的无向图),每个点有一个整数权值,第i个点的权值是 a_i.现在有m个操作,每个操作如下: 操作1(修改):给定 ...

  6. 洛谷P4458 /loj#2512.[BJOI2018]链上二次求和(线段树)

    题面 传送门(loj) 传送门(洛谷) 题解 我果然是人傻常数大的典型啊-- 题解在这儿 //minamoto #include<bits/stdc++.h> #define R regi ...

  7. loj2512 [BJOI2018]链上二次求和

    传送门 分析 咕咕咕 代码 #include<iostream> #include<cstdio> #include<cstring> #include<st ...

  8. 「BJOI2018」链上二次求和

    「BJOI2018」链上二次求和 https://loj.ac/problem/2512 我说今天上午写博客吧.怕自己写一上午,就决定先写道题. 然后我就调了一上午线段树. 花了2h找到lazy标记没 ...

  9. [bzoj5291]链上二次求和

    记$bi=b_{i-1}+ai$,$ci=c_{i-1}+bi$,那么答案就是$\sum_{i=l}^{r}\sum_{j=0}^{n-i}b_{j+i}-bj=(r-l+1)cn-\sum_{i=l ...

随机推荐

  1. 动态加载与插件系统的初步实现(三):WinForm示例

    代码文件在此Download,本文章围绕前文所述默认AppDomain.插件容器AppDomain两个域及IPlugin.PluginProvider.PluginProxy3个类的使用与变化进行. ...

  2. linux增加硬盘 磁盘分区格式化及挂载

    nux磁盘分区格式化及挂载 意义: 给linux 系统服务器扩容, 加一块硬盘 实验环境: virtualBox虚拟软件  + centos6.5 第一步: 添加硬件 硬盘 (我这里用virtualB ...

  3. gitlab 配置 ssh key

    打开本地git bash,使用如下命令生成ssh公钥和私钥对 ssh-keygen -t rsa -C 'xxx@xxx.com' 然后一路回车(-C 参数是你的邮箱地址) 然后打开~/.ssh/id ...

  4. 图像处理和OpenCV初步

    图像从数学和计算机的角度理解就是一个矩阵,矩阵中的每一个元素叫做像素,又由于图像有灰度图像和彩色图像之分,所以图像在矩阵的基础上引入通道(channel),其中色彩用数字来表示的时候,规定数字0表示黑 ...

  5. Java 浅拷贝 深拷贝

    两者区别主要在于引用数据类型的属性,对于基本数据类型采用的是值传递,所以两者一样: 对于浅拷贝,引用数据类型只会进行引用传递,即复制一份引用值(内存地址)给新对象,一个对象的变化会影响到另一个的引用属 ...

  6. vue 使用ref获取DOM元素和组件引用

    在vue中可以通过ref获取dom元素,并操作它,还可以获取组件里面的数据和方法. HTML部分: <div id="app"> <input type=&quo ...

  7. vue 自定义全局按键修饰符

    在监听键盘事件时,我们经常需要检查常见的键值.Vue 允许为 v-on 在监听键盘事件时添加按键修饰符: JS部分: Vue.config.keyCodes = { f2:113, } var app ...

  8. Netty源码分析第6章(解码器)---->第1节: ByteToMessageDecoder

    Netty源码分析第六章: 解码器 概述: 在我们上一个章节遗留过一个问题, 就是如果Server在读取客户端的数据的时候, 如果一次读取不完整, 就触发channelRead事件, 那么Netty是 ...

  9. awk之close函数

    echo "21 2 " | awk '{ first[NR]=$ second[NR]=$ }END{ print "======打印第1列并排序:========== ...

  10. java后端面试题汇总

    转载链接:https://www.nowcoder.com/discuss/90776?type=0&order=0&pos=23&page=0 基础篇 数据结构与算法 线性表 ...