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

  考虑区间[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. java基础解析系列(三)---HashMap

    java基础解析系列(三)---HashMap java基础解析系列 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)-- ...

  2. d-ary heap实现一个快速的优先级队列(C#)

    d-ary heap简介: d-ary heap 是泛化版本的binary heap(d=2),d-ary heap每个非叶子节点最多有d个孩子结点. d-ary heap拥有如下属性: 类似comp ...

  3. 第十周psp作业

    本周psp 本周进度条 代码累积折线图 博文字数累积折线图 饼状图

  4. oracle和mysql对时间与字符串的转换

    1,oracle to_date(#{item.value},'YYYY-MM-DD hh24-mi-ss') to_char(CRERATE_TIME,'YYYY-MM-DD hh24-mi-ss' ...

  5. TeamWork#3,Week5,Scrum Meeting 11.9

    由于经验不足和储备知识不够,最近我们的项目遇到了一些技术问题,需要对项目进行重新计划.我们总结了经验教训,找出了问题所在,明确了要补充的知识,加紧学习,将会在一周之内解决相关问题. 成员 已完成 待完 ...

  6. 20162325 金立清 S2 W9 C18

    20162325 2017-2018-2 <程序设计与数据结构>第9周学习总结 教材学习内容概要 堆是一棵完全二叉树,其中每个元素大于等于其所有子结点的值. 向堆中添加一个元素的方法是,首 ...

  7. 冲刺One之站立会议5 /2015-5-18

    2015-5-18 服务器部分大体已经完工,现在我们主要是在把登陆界面和服务器组装起来,这个过程是很让人头痛的,以为其中涉及到了很多网络协议.网络编程的知识,由于之前我们没有接触过所以实现起来会觉得很 ...

  8. "私人助手"NABCD分析

    ---恢复内容开始--- 团队开发项目“私人助手”需求分析NABCD模型: (1)N(Need需求):“私人助手”解决了几类人遇到非常多的事情,非常繁琐,“私人助手”为用户解决这个问题,让用户的工作更 ...

  9. 剑指offer :从尾到头打印链表

    题目描述: 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. 解题思路: 链表的遍历只能从头向尾进行,要从尾到头输出,考虑用栈.先从头到尾遍历一次链表,同时将值进栈,再清空栈,同时将值 ...

  10. HTML和CSS <h1> --1-- <h1>

    Html和CSS的关系 学习web前端开发基础技术需要掌握:HTML.CSS.JavaScript语言.下面我们就来了解下这三门技术都是用来实现什么的: 1. HTML是网页内容的载体.内容就是网页制 ...