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

原文链接http://www.cnblogs.com/zhouzhendong/p/9031130.html

题目传送门 - LOJ#2512

题目传送门 - 洛谷P4458

题目传送门 - BZOJ5291

推荐LOJ和洛谷,题面质量好,而且不卡常数。

BZOJ题面烂,而且要卡那么一点点常数。

题意

  有一条长度为$n$的链$\forall 1≤i<n$,点$i$与点$i+1$之间有一条边的无向图),每个点有一个整数权值,第$i$个点的权值是$a_i$??。现在有$m$个操作,每个操作如下:

  操作 1(修改):给定链上两个节点$u$、$v$和一个整数$d$,表示将链上$u$到$v$唯一的简单路径上每个点权值都加上$d$。

  操作 2(询问):给定两个正整数$L$、$R$,表示求链上所有节点个数大于等于$L$且小于等于$R$的简单路径节点权值和之和。由于答案很大,只用输出对质数$1000000007$取模的结果即可。

  一条节点个数为$k$的简单路径节点权值和为这条上所有$k$个节点(包括端点)的权值之和,而本题中要求是对所有满足要求的简单路径,求这一权值和的和。

  由于是无向图,路径也是无向的,即点$1$到点$2$的路径与点$2$到点$1$的路径是同一条,不要重复计算。

题解

  记$S_x[i]=\sum_{j=1}^{i} x[j]$,则我们现在来推一下式子。

  对于询问,我们要求的是:

  $$\begin{align*}\sum_{i=L}^{R}\sum_{j=i}^{n}S_a[j]-S_a[j-i]&=\sum_{i=L}^{R}(\sum_{j=i}^{n}S_a[j]-\sum_{j=0}^{n-i}S_a[j])\\&=\sum_{i=L}^{R}(S_{S_a}[n]-S_{S_a}[i-1]-S_{S_a}[n-i])\\&=(R-L+1)S_{S_a}[n]-\sum_{i=L-1}^{R-1}S_{S_a}[i]-\sum_{n-R}^{n-L}S_{S_a}[i]\end{align*}$$

  只需要维护$S_{S_a}$的前缀和就可以了。

  考虑分类讨论区间加对$S_{S_a}$的贡献。

  在$L$~$R$区间加$v$的贡献为:

  记$len=R-L+1$,

  对于$L\leq i\leq R$,$S_{S_a}[i]=S_{S_a}[i]+\cfrac{(i-L+1)(i-L+2)}{2}v$。

  对于$i>R$,$S_{S_a}[i]=S_{S_a}[i]+\cfrac{len(len+1)}{2}v+len(i-R)v$。

  注意一下,对于修改,$L$和$R$可能是$L>R$的,我这里默认了$L\leq R$。

  于是这个区间加对于$S_{S_a}$的贡献可以转化成一个关于$i$的二次函数。

  可以用线段树来维护。

  在BZOJ上面,略微卡一点常数。建议在标记下传的时候,如果三个标记都为$0$就直接退出。

题解参考了:https://blog.csdn.net/cdsszjj/article/details/80286084

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=200005;
const LL mod=1e9+7;
int n,m,a[N];
LL cv1[N],cv2[N];
struct Seg{
	LL v,v0,v1,v2;
	LL s0,s1,s2;
}t[N<<2];
void build(int rt,int L,int R){
	t[rt].v0=t[rt].v1=t[rt].v2=0;
	t[rt].s0=R-L+1;
	if (L>0){
		t[rt].s1=(cv1[R]-cv1[L-1]+mod)%mod;
		t[rt].s2=(cv2[R]-cv2[L-1]+mod)%mod;
	}
	else
		t[rt].s1=cv1[R],t[rt].s2=cv2[R];
	if (L==R){
		t[rt].v=a[L];
		return;
	}
	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
	build(ls,L,mid);
	build(rs,mid+1,R);
	t[rt].v=(t[ls].v+t[rs].v)%mod;
}
void addrt(int rt,LL d0,LL d1,LL d2){
	t[rt].v=(t[rt].v+d0*t[rt].s0+d1*t[rt].s1+d2*t[rt].s2)%mod;
	t[rt].v0=t[rt].v0+d0;
	t[rt].v1=t[rt].v1+d1;
	t[rt].v2=t[rt].v2+d2;
	if (t[rt].v0>=mod)t[rt].v0-=mod;
	if (t[rt].v1>=mod)t[rt].v1-=mod;
	if (t[rt].v2>=mod)t[rt].v2-=mod;
}
void pushdown(int rt){
	if (!t[rt].v0&&!t[rt].v1&&!t[rt].v2)
		return;
	int ls=rt<<1,rs=ls|1;
	addrt(ls,t[rt].v0,t[rt].v1,t[rt].v2);
	addrt(rs,t[rt].v0,t[rt].v1,t[rt].v2);
	t[rt].v0=t[rt].v1=t[rt].v2=0;
}
void update(int rt,int L,int R,int xL,int xR,LL d0,LL d1,LL d2){
	if (xL>xR)
		return;
	if (xL<=L&&R<=xR){
		addrt(rt,d0,d1,d2);
		return;
	}
	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
	pushdown(rt);
	if (xR<=mid)
		update(ls,L,mid,xL,xR,d0,d1,d2);
	else if (xL>mid)
		update(rs,mid+1,R,xL,xR,d0,d1,d2);
	else {
		update(ls,L,mid,xL,mid,d0,d1,d2);
		update(rs,mid+1,R,mid+1,xR,d0,d1,d2);
	}
	t[rt].v=(t[ls].v+t[rs].v)%mod;
}
LL query(int rt,int L,int R,int xL,int xR){
	if (xL>xR)
		return 0;
	if (xL<=L&&R<=xR)
		return t[rt].v;
	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
	pushdown(rt);
	if (xR<=mid)
		return query(ls,L,mid,xL,xR);
	else if (xL>mid)
		return query(rs,mid+1,R,xL,xR);
	else
		return (query(ls,L,mid,xL,xR)+query(rs,mid+1,R,xL,xR))%mod;
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++){
		cv1[i]=(cv1[i-1]+i)%mod;
		cv2[i]=(cv2[i-1]+1LL*i*i)%mod;
	}
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]),a[i]=(a[i]+a[i-1])%mod;
	for (int i=1;i<=n;i++)
		a[i]=(a[i]+a[i-1])%mod;
	build(1,1,n);
	for (int i=1;i<=m;i++){
		int opt,L,R;
		LL v;
		scanf("%d%d%d",&opt,&L,&R);
		if (L>R)
			swap(L,R);
		if (opt==2){
			L=max(L,1);
			LL s1=query(1,1,n,n,n)*(R-L+1)%mod;
			LL s2=query(1,1,n,max(L-1,1),R-1);
			LL s3=query(1,1,n,max(n-R,1),n-L);
			printf("%lld\n",(s1-s2-s3+mod+mod+mod)%mod);
		}
		else {
			scanf("%lld",&v);
			LL len=R-L+1,iv2=500000004,vv=v*iv2%mod;
			update(1,1,n,L,R,vv*(L-1)%mod*(L-2)%mod,vv*(3-2*L+mod)%mod,vv);
			update(1,1,n,R+1,n,((len*(len+1)/2%mod*v-len*v%mod*R)%mod+mod)%mod,v*len%mod,0);
		}
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/zhouzhendong/p/9031130.html

时间: 2024-10-04 00:04:24

BZOJ5291/洛谷P4458/LOJ#2512 [Bjoi2018]链上二次求和 线段树的相关文章

[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}^{r-1}ci-\sum_{i=n-r}^{n-l}ci$,用线段树维护ci数组考虑对于[l,r,v]的修改操作(记$L=r-l+1$,注意不保证$l\le r$),影响分为两部分:1.$r<i$的部分,化简得到为$ci+=Lv\cdot i-L(l+r-2)v/2$2.$l\le i\le

【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树

题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点. 输入 第一行有两个整数N,Q(1 ≤N≤ 100,000:1 ≤Q≤ 200,000),分别表示节点个数和操作个数. 下面一行N个整数,表示初始时每个节点的初始值. 接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树).

[Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086

额... 首先,看到这道题,第一想法就是二分答案+线段树... 兴高采烈的认为我一定能AC,之后发现n是500000... nlog^2=80%,亲测可过... 由于答案是求满足题意的最大长度-最小长度最小,那么我们可以考虑将区间按长度排序 之后,因为我们是需要最大最小,所以,我们必定选择在排完序的区间上取连续的一段是最优情况(起码不会比别的差) 因此,考虑双指针扫一下就可以了... 是不是很水? 由于懒得写离散化,一开始写的动态开点线段树,我*****什么鬼?mle?!256mb开不下! lo

树链剖分(以维护线段树为例)

关于树链剖分的有关知识:http://www.cnblogs.com/sagitta/p/5660749.html 以下是洛谷p3384经过无数次WA和RE(最后发现只是有一个函数的调用写反了qwq)终于AC的代码: #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<climits> #in

洛谷 P1507 NASA的食物计划 【二维费用背包】+【01背包】

题目链接:https://www.luogu.org/problemnew/show/P1507 题目背景 NASA(美国航空航天局)因为航天飞机的隔热瓦等其他安全技术问题一直大伤脑筋,因此在各方压力下终止了航天飞机的历史,但是此类事情会不会在以后发生,谁也无法保证,在遇到这类航天问题时,解决方法也许只能让航天员出仓维修,但是多次的维修会消耗航天员大量的能量,因此NASA便想设计一种食品方案,让体积和承重有限的条件下多装载一些高卡路里的食物. 题目描述 航天飞机的体积有限,当然如果载过重的物品,

loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)

题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se second #define pb push_back #define bit bitset<B + 1> using namespace std; const int MAXN = 501, B = 1001, SS = 4001; inline int read() { char c = getchar

洛谷P3379 【模板】最近公共祖先(LCA)(树链剖分)

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 复制 5 5 4 3 1 2 4

洛谷.3803.[模板]多项式乘法(FFT)

题目链接:洛谷.LOJ. FFT相关:快速傅里叶变换(FFT)详解.FFT总结.从多项式乘法到快速傅里叶变换. #include <cmath> #include <cctype> #include <cstdio> #include <algorithm> #define gc() getchar() const int N=1e6+5; const double PI=acos(-1); int n,m; struct Complex { double

洛谷 U4792 Acheing 单调队列

/*洛谷 U4792 Acheing 二维线段树 n*n*logn*logn T成傻逼2333 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 1010 #define lc k*2 #define rc k*2+1 #define mid (l+r)/2 using namespace std; int n,m,k,g[maxn][maxn],x,y,z; int x1,x2,