Transformation HDU - 4578(线段树or暴力分块)

传送门
做这题之前最好先做一下这题 洛谷 线段树2
说回来这题,比起线段树2,其实就多了一个操作,求幂方和.区间赋值是可以由前两个操作推导出来的,我们先×0在+x就可以了.考虑如何求幂方和
因为线段树维护的信息要满足区间可加性.幂方和是满足的.所以就维护吧.
我们维护三个sum,一个一次幂,一个二次幂,一个三次幂,记为s1,s2,s3.
这三个的维护s1其实就是区间和.s2和s3推导一下就可以得到维护的公式了.因为只有区间加和区间乘,只要在这两个操作的时候顺便维护一下s1s2s3就行了.s1很好维护,区间乘也很好维护,讲一下s2的区间加(同理可得s3的区间加).
al - ar + d. 平方和即是(al+d)2.展开(al2+2d×al+d2).那整体就是加了2d×s1+d2×len(len是区间的长度).s3同理.
线段树敲不熟练的用暴力分块也一样可以做.8s的时限应该勉强够用
线段树代码

#pragma GCC optimize(2)
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=b;++i)
#define afir(i,a,b) for(int i=a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define L 2*i
#define R 2*i+1
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;
const int p = 1e4+7;

inline int read(){
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
struct Tree{
	int l,r;
	LL add,mul,s[3],len;
}tree[N*4];
LL a[N];
void push_up(int i){
	tree[i].s[0] = tree[L].s[0] + tree[R].s[0];
	tree[i].s[1] = tree[L].s[1] + tree[R].s[1];
	tree[i].s[2] = tree[L].s[2] + tree[R].s[2];
}
void push_add(int i,LL v){
	LL s[3],len = tree[i].len;
	s[0] = tree[i].s[0];s[1] = tree[i].s[1];s[2] = tree[i].s[2];
	tree[i].s[0] = (s[0] + v*len)%p;
	tree[i].s[1] = (s[1] + (2*v*s[0] + v*v*len%p))%p;
	tree[i].s[2] = (s[2] + (v*v*v*len%p + 3*v*v*s[0]%p + 3*v*s[1]%p))%p;
}
void push_mul(int i,LL v){
	LL s[3];
	s[0] = tree[i].s[0];s[1] = tree[i].s[1];s[2] = tree[i].s[2];
	tree[i].s[0] = s[0]*v%p;
	tree[i].s[1] = s[1]*v*v%p;
	tree[i].s[2] = s[2]*v*v*v%p;
}
void push_down(int i){
	LL add = tree[i].add,mul = tree[i].mul;
	if(mul != 1){
		tree[L].add = tree[L].add*mul%p;
		tree[R].add = tree[R].add*mul%p;
		tree[L].mul = tree[L].mul*mul%p;
		tree[R].mul = tree[R].mul*mul%p;
		push_mul(L,mul);
		push_mul(R,mul);
	}
	if(add){
		tree[L].add = (tree[L].add + add)%p;
		tree[R].add = (tree[R].add + add)%p;
		push_add(L,add);
		push_add(R,add);
	}
	tree[i].add = 0; tree[i].mul = 1;
}
void build(int i,int l,int r){
	tree[i] = {l,r,0,1,0,0,0,r-l+1};
	if(l >= r) return;
	int mid = l + r >> 1;
	build(L,l,mid);
	build(R,mid+1,r);
}
void Add(int i,int l,int r,LL v){
	if(tree[i].l >= l && tree[i].r <= r){
		tree[i].add = (tree[i].add + v)%p;
		push_add(i,v);
		return;
	}
	push_down(i);
	int mid = tree[i].l + tree[i].r >> 1;
	if(r <= mid) Add(L,l,r,v);
	else if(l > mid) Add(R,l,r,v);
	else{
		Add(L,l,mid,v);
		Add(R,mid+1,r,v);
	}
	push_up(i);
}
void Mul(int i,int l,int r,LL v){
	if(tree[i].l >= l && tree[i].r <= r){
		tree[i].add = tree[i].add*v%p;
		tree[i].mul = tree[i].mul*v%p;
		push_mul(i,v);
		return;
	}
	push_down(i);
	int mid = tree[i].l + tree[i].r >> 1;
	if(r <= mid) Mul(L,l,r,v);
	else if(l > mid) Mul(R,l,r,v);
	else{
		Mul(L,l,mid,v);
		Mul(R,mid+1,r,v);
	}
	push_up(i);
}
LL query(int i,int l,int r,int v){
	if(tree[i].l >= l && tree[i].r <= r) return tree[i].s[v];
	push_down(i);
	int mid = tree[i].l + tree[i].r >> 1;
	if(r <= mid) return query(L,l,r,v);
	else if(l > mid) return query(R,l,r,v);
	else return (query(L,l,mid,v) + query(R,mid+1,r,v))%p;
}
int main(){
	int n,m;
	while(1){
		n = read();m = read();
		if(!n && !m) break;
		build(1,1,n);
		while(m--){
			int op,l,r,v;
			op = read();l = read();r = read();v = read();
			if(op == 1) Add(1,l,r,v);
			else if(op == 2) Mul(1,l,r,v);
			else if(op == 3){
				Mul(1,l,r,0);
				Add(1,l,r,v);
			}
			else printf("%lld\n",query(1,l,r,v-1));
		}
	}
	
	return 0;
}	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值