洛谷P4458 /loj#2512.[BJOI2018]链上二次求和(线段树)
题面
题解
我果然是人傻常数大的典型啊……
//minamoto
#include<bits/stdc++.h>
#define R register
#define ls (p<<1)
#define rs (p<<1|1)
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int K=-1,Z=0;
inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
void print(R int x){
if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++K]=z[Z],--Z);sr[++K]='\n';
}
const int N=2e5+5,P=1e9+7,inv2=500000004,inv6=166666668;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
return res;
}
struct node{int l,r,a,b,sum[2];}tr[N<<2];
int a[N],n,m;
inline int f(R int x){return 1ll*x*(x+1)%P*((x<<1ll)+1)%P*inv6%P;}
void ppd(int p,int a,int b){
int sz=tr[p].r-tr[p].l;
tr[p].sum[0]=add(tr[p].sum[0],1ll*add(mul(2,a),mul(b,sz))*(sz+1)%P*inv2%P);
tr[p].sum[1]=add(tr[p].sum[1],1ll*a*(tr[p].l+tr[p].r)%P*(sz+1)%P*inv2%P);
tr[p].sum[1]=add(tr[p].sum[1],1ll*tr[p].l*b%P*sz%P*(sz+1)%P*inv2%P);
tr[p].sum[1]=add(tr[p].sum[1],mul(b,f(sz)));
tr[p].a=add(tr[p].a,a),tr[p].b=add(tr[p].b,b);
}
void upd(int p){
tr[p].sum[0]=add(tr[ls].sum[0],tr[rs].sum[0]);
tr[p].sum[1]=add(tr[ls].sum[1],tr[rs].sum[1]);
}
void pd(int p){
int mid=(tr[p].l+tr[p].r)>>1;
ppd(ls,tr[p].a,tr[p].b);
ppd(rs,add(tr[p].a,mul(mid-tr[p].l+1,tr[p].b)),tr[p].b);
tr[p].a=tr[p].b=0;
}
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
if(l==r)return tr[p].sum[0]=a[l],tr[p].sum[1]=mul(l,a[l]),void();
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
upd(p);
}
int query(int p,int ql,int qr,int id){
if(ql<=tr[p].l&&qr>=tr[p].r)return tr[p].sum[id];
int mid=(tr[p].l+tr[p].r)>>1;
if(tr[p].a||tr[p].b)pd(p);
int res=0;
if(ql<=mid)res=add(res,query(ls,ql,qr,id));
if(qr>mid)res=add(res,query(rs,ql,qr,id));
return res;
}
void update(int p,int l,int r,int a,int b){
if(l==tr[p].l&&r==tr[p].r)return ppd(p,a,b);
if(tr[p].a||tr[p].b)pd(p);
int mid=(tr[p].l+tr[p].r)>>1;
if(r<=mid)update(ls,l,r,a,b);
else if(l>mid)update(rs,l,r,a,b);
else update(ls,l,mid,a,b),update(rs,mid+1,r,add(a,mul(b,mid+1-l)),b);
upd(p);
}
int calc(int x){
if(!x)return 0;
int res=0;
res=add(res,mul(query(1,x,n,0),x));
if(x!=n)res=add(res,P-mul(query(1,1,n-x,0),x));
if(x!=1)res=add(res,query(1,1,x-1,1));
res=add(res,P-add(mul(n,query(1,n-x+1,n,0)),P-query(1,n-x+1,n,1)));
return res;
}
int main(){
// freopen("testdata.in","r",stdin);
n=read(),m=read();
fp(i,1,n)a[i]=read(),a[i]=add(a[i],a[i-1]);
build(1,1,n);
int op,l,r,d;
while(m--){
op=read(),l=read(),r=read();
if(op==1){
d=read();if(l>r)swap(l,r);
update(1,l,r,d,d);
if(r<n)update(1,r+1,n,mul(d,r-l+1),0);
}else print(dec(calc(r),calc(l-1)));
}
return Ot(),0;
}
洛谷P4458 /loj#2512.[BJOI2018]链上二次求和(线段树)的更多相关文章
- BZOJ5291/洛谷P4458/LOJ#2512 [Bjoi2018]链上二次求和 线段树
原文链接http://www.cnblogs.com/zhouzhendong/p/9031130.html 题目传送门 - LOJ#2512 题目传送门 - 洛谷P4458 题目传送门 - BZOJ ...
- [BZOJ5291][BJOI2018]链上二次求和(线段树)
感觉自己做的麻烦了,但常数似乎不算差.(只是Luogu最慢的点不到2s本地要跑10+s) 感觉我的想法是最自然的,但不明白为什么网上似乎找不到这种做法.(不过当然所有的做法都是分类大讨论,而我的方法手 ...
- 【BZOJ5291】[BJOI2018]链上二次求和(线段树)
[BZOJ5291][BJOI2018]链上二次求和(线段树) 题面 BZOJ 洛谷 题解 考虑一次询问\([l,r]\)的答案.其中\(S\)表示前缀和 \(\displaystyle \sum_{ ...
- bzoj 5291: [Bjoi2018]链上二次求和
Description 有一条长度为n的链(1≤i<n,点i与点i+1之间有一条边的无向图),每个点有一个整数权值,第i个点的权值是 a_i.现在有m个操作,每个操作如下: 操作1(修改):给定 ...
- BZOJ5291 BJOI2018链上二次求和(线段树)
用线段树对每种长度的区间维护权值和. 考虑区间[l,r]+1对长度为k的区间的贡献,显然其为Σk-max(0,k-i)-max(0,k-(n-i+1)) (i=l~r). 大力展开讨论.首先变成Σk- ...
- 2018.01.04 bzoj5291: [Bjoi2018]链上二次求和(线段树)
传送门 线段树基础题. 题意:给出一个序列,要求支持区间加,查询序列中所有满足区间长度在[L,R][L,R][L,R]之间的区间的权值之和(区间的权值即区间内所有数的和). 想题555分钟,写题202 ...
- loj2512 [BJOI2018]链上二次求和
传送门 分析 咕咕咕 代码 #include<iostream> #include<cstdio> #include<cstring> #include<st ...
- 「BJOI2018」链上二次求和
「BJOI2018」链上二次求和 https://loj.ac/problem/2512 我说今天上午写博客吧.怕自己写一上午,就决定先写道题. 然后我就调了一上午线段树. 花了2h找到lazy标记没 ...
- 洛谷P4459/loj#2511 [BJOI2018]双人猜数游戏(博弈论)
题面 传送门(loj) 传送门(洛谷) 题解 所以博弈论的本质就是爆搜么-- 题解 //minamoto #include<bits/stdc++.h> #define R registe ...
随机推荐
- left join的多重串联与groupby
有三张表或组合查询,f1,f2,f3,其中,f1分别与f2,f3是一对多关系,f1一条记录可能对应f2或f3中0条或多条记录 要创建一个查询,以f1为基准,即f1中有多少条记录,结果也就返回对应数量的 ...
- linux安装xgboost
在学校服务器上安装xgboost,事先我已经安装了anaconda,但是因为师兄已经装了python所以没加入到path. 网上的方法一般都要编译,另外官方的下载方法要联网..总之出了一堆错,最终还是 ...
- python--numpy学习(一)
NumPy 部分功能如下: ndarray,一个具有矢量运算符和复杂广播能力的快速节省空间的多维数组 用于对数组数据进行快速运算的标准数学函数 用于读写磁盘数据的工具以及用于操作内存映射文件的工具 线 ...
- ClientDataSet1.LoadFromStream
lStream3.Position := 0; lDataSet.LoadFromStream(lStream3);
- jQuery Validate自定义验证方法实现方式
对应调用函数: ( 可以在内部写js/或者外部引入-我是外部引入的文件 ) validate.expand.js // JavaScript Document //检测手机号是否正确 jQuery. ...
- 编译错误error: invalid&nbsp…
昨天遇到一个莫名其妙的编译错误,以前没有见过,而且代码流程看起来也没有太多的奇异之处.后来忍无可忍,百度了下,发现别人也有遇到这个错误的,他的解决方法是:少了"}". 嘿嘿,我开始 ...
- Unity3d平台信息设置
[Unity3d平台信息设置] 通过"Edit" -> "Project Settings" -> "Player"菜单选项.打 ...
- Newtonsoft 序列化和反序列化特殊处理
1>序列化,时间格式化处理 JsonConvert.SerializeObject(Iar, new JsonSerializerSettings() { DateFormatString = ...
- numpy ndarray 返回 index 问题
经常遇到需要返回满足条件的index. python中没有which函数,但有列表推导式, 可以实现类似功能 y= np.array([3,2,5,20]) yOut[131]: array([ 3, ...
- Java学习——JSTL标签与EL表达式之间的微妙关系
原文总结的太好了,忍不住记录.转发. 原文地址:http://blog.csdn.net/u010168160/article/details/49182867 目录(?)[-] 一EL表达式 EL相 ...