我是靠谱客的博主 妩媚小蜜蜂,最近开发中收集的这篇文章主要介绍2018.10.22【COGS2633】数列操作e(线段树)传送门解析:,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

传送门


解析:

输出又一次阻挡了我一A的步伐。。。

思路:

线段树维护区间加二次函数,区间求和。

题目中要求的加操作是在第iii个位置加上(i−l+1)2×v(i-l+1)^2times v(il+1)2×v,显然我们需要展开成二次函数一般形式,这样才能够令它满足加法性质,便于合并标记。

展开后以iii为主元就是i2∗v+i∗(2∗v∗(1−pos))+(pos−1)2∗vi^2*v+i*(2*v*(1-pos))+(pos-1)^2*vi2v+i(2v(1pos))+(pos1)2v,显然这三个多项式的合并都可以直接加法,并且我们预处理平方前缀和可以做到O(1)O(1)O(1)计算出者三个的区间和,具体实现就在代码里面。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define ull unsigned ll

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

cs int N=100005;

ull sum[N<<2],A[N<<2],B[N<<2],C[N<<2];
ull square[N];

inline void pushnow(int k,int l,int r,cs ull &a,cs ull &b,cs ull &c){
	sum[k]+=(r-l+1)*a+(1ll*r-l+1)*(l+r)/2*b+(square[r]-square[l-1])*c;
	A[k]+=a;B[k]+=b;C[k]+=c;
}

inline void pushdown(int k,int l,int r){
	if(A[k]||B[k]||C[k]){
		int mid=(l+r)>>1;
		pushnow(k<<1,l,mid,A[k],B[k],C[k]);
		pushnow(k<<1|1,mid+1,r,A[k],B[k],C[k]);
		A[k]=B[k]=C[k]=0;
	}
}

inline void pushup(int k){
	sum[k]=sum[k<<1]+sum[k<<1|1];
}

void modify(int k,int l,int r,cs int &ql,cs int &qr,cs ull &pos,cs ull &v){
	if(ql<=l&&r<=qr)return pushnow(k,l,r,(pos-1)*(pos-1)*v,v*2*(1-pos),v);
	pushdown(k,l,r);
	int mid=(l+r)>>1;
	if(ql<=mid)modify(k<<1,l,mid,ql,qr,pos,v);
	if(qr>mid)modify(k<<1|1,mid+1,r,ql,qr,pos,v);
	pushup(k);
}

ull query(int k,int l,int r,cs int &ql,cs int &qr){
	if(ql<=l&&r<=qr)return sum[k];
	int mid=(l+r)>>1;
	pushdown(k,l,r);
	if(ql>mid)return query(k<<1|1,mid+1,r,ql,qr);
	if(qr<=mid)return query(k<<1,l,mid,ql,qr);
	return query(k<<1,l,mid,ql,qr)+query(k<<1|1,mid+1,r,ql,qr);
}

ull ans;
int n,m;
signed main(){
	freopen("rneaty.in","r",stdin);
	freopen("rneaty.out","w",stdout);
	n=getint();
	m=getint();
	for(int re i=1;i<=n;++i)square[i]=square[i-1]+(ull)i*i;
	while(m--){
		int op=getint(),l=getint(),r=getint();
		switch(op){
			case 1:{
				ull x=getint();
				modify(1,1,n,l,r,l,x);
				break;
			}
			case 2:{
				ans^=query(1,1,n,l,r);
				break;
			}
		}
	}
	printf("%llu",ans);
	return 0;
}

转载于:https://www.cnblogs.com/zxyoi/p/10047177.html

最后

以上就是妩媚小蜜蜂为你收集整理的2018.10.22【COGS2633】数列操作e(线段树)传送门解析:的全部内容,希望文章能够帮你解决2018.10.22【COGS2633】数列操作e(线段树)传送门解析:所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部