线段树例题

区间乘区间加区间询问

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
struct Node{
	int l,r;
	long long sum;
	long long mut,add;
}tr[N << 2];
int a[N];
long long p;
void pushup(int u){
	tr[u].sum = (tr[u << 1].sum + tr[u << 1 | 1].sum) % p;
}
void pushdown(int u){
	tr[u << 1].sum = (tr[u << 1].sum * tr[u].mut % p + tr[u].add * (tr[u << 1].r - tr[u << 1].l + 1) % p) % p;
	tr[u << 1].add = (tr[u << 1].add * tr[u].mut % p + tr[u].add) % p;
	tr[u << 1].mut = (tr[u << 1].mut * tr[u].mut) % p;
	tr[u << 1 | 1].sum = (tr[u << 1 | 1].sum * tr[u].mut + tr[u].add * (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) % p) % p;
	tr[u << 1 | 1].add = (tr[u << 1 | 1].add * tr[u].mut % p + tr[u].add) % p;
	tr[u << 1 | 1].mut = (tr[u << 1 | 1].mut * tr[u].mut) % p;
	tr[u].add = 0;
	tr[u].mut = 1;
}
void build(int u,int l,int r){
	tr[u].l = l;
	tr[u].r = r;
	tr[u].mut = 1;
	if(l == r){
		tr[u].sum = a[l];
		return;
	}
	int mid = l + r >> 1;
	build(u << 1,l,mid);
	build(u << 1 | 1,mid + 1,r);
	pushup(u);
}
void modify1(int u,int l,int r,int t){
	if(l <= tr[u].l && tr[u].r <= r){
		tr[u].add = (tr[u].add * t) % p;
		tr[u].mut = (tr[u].mut * t) % p;
		tr[u].sum = (tr[u].sum * t) % p;
		return;
	}
	pushdown(u);
	int mid = tr[u].l + tr[u].r >> 1;
	if(l <= mid) modify1(u << 1,l,r,t);
	if(r > mid) modify1(u << 1 | 1,l,r,t);
	pushup(u);
}
void modify2(int u,int l,int r,int t){
	if(l <= tr[u].l && tr[u].r <= r){
		tr[u].add = (tr[u].add + t) % p;
		tr[u].sum = (tr[u].sum + (tr[u].r - tr[u].l + 1) * t) % p;
		return;
	}
	pushdown(u);
	int mid = tr[u].l + tr[u].r >> 1;
	if(l <= mid) modify2(u << 1,l,r,t);
	if(r > mid) modify2(u << 1 | 1,l,r,t);
	pushup(u);
}
long long query(int u,int l,int r){
	if(l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
	pushdown(u); 
	int mid = tr[u].l + tr[u].r >> 1;
	long long sum = 0;
	if(l <= mid) sum = query(u << 1,l,r);
	if(r > mid) sum = (sum + query(u << 1 | 1,l,r)) % p;
	return sum;
}
int main(){
	int n,m;
	cin >> n >> p;
	for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);
	build(1,1,n);
	cin >> m;
//	cout << query(1,2,4) << endl;
	for(int i = 1;i <= m;i ++){
		int k;
		scanf("%d",&k);
		if(k == 1){
			int l,r,t;
			scanf("%d%d%d",&l,&r,&t);
			modify1(1,l,r,t);
		}
		if(k == 2){
			int l,r,t;
			scanf("%d%d%d",&l,&r,&t);
			modify2(1,l,r,t);
		}
		if(k == 3){
			int l,r;
			scanf("%d%d",&l,&r);
			printf("%lld\n",query(1,l,r));
		}
	}
	return 0;
}

无需pushdown的扫描线

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5;
struct query{
	double x,y1,y2;
	int k;
	bool operator <(const query &t) const{
		return x < t.x;
	};
	
}q[N << 1];
struct Node{
	int l,r;
	int cnt;
	double len;
}tr[N << 3];
vector <double> vs;
int find(double y){
	return lower_bound(vs.begin(),vs.end(),y) - vs.begin();
}
void build(int u,int l,int r){
	if(l == r){
		tr[u] = {l,r,0,0};
	}else{
		tr[u] = {l,r,0,0};
		int mid = l + r >> 1;
		build(u << 1,l,mid);
		build(u << 1 | 1,mid + 1,r);
	}
}
void pushup(int u){
	if(tr[u].cnt) tr[u].len = vs[tr[u].r + 1] - vs[tr[u].l];
	else if(tr[u].l != tr[u].r) tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len;
	else tr[u].len = 0;
}
void modify(int u,int l,int r,int k){
	if(l <= tr[u].l && tr[u].r <= r){
		tr[u].cnt += k;
		pushup(u);
	}else{
		int mid = tr[u].l + tr[u].r >> 1;
		if(l <= mid) modify(u << 1,l,r,k);
		if(r > mid) modify(u << 1 | 1,l,r,k);
		pushup(u);
	}
}
int main(){
	int n;
	int T = 1;
	while(scanf("%d",&n),n){
		vs.clear();
		for(int i = 1,j = 0;i <= n;i ++){
			double x1,y1,x2,y2;
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			q[++ j] = {x1,y1,y2,1};
			q[++ j] = {x2,y1,y2,-1};
			vs.push_back(y1);
			vs.push_back(y2);
		}
		sort(vs.begin(),vs.end());
		vs.erase(unique(vs.begin(),vs.end()),vs.end());
		build(1,0,vs.size() - 2);
		sort(q + 1,q + 2 * n  + 1);
		double res = 0;
		for(int i = 1;i <= 2 * n;i ++){
			if(i > 1) res += tr[1].len * (q[i].x - q[i - 1].x);
			modify(1,find(q[i].y1),find(q[i].y2) - 1,q[i].k);
		}
		printf("Test case #%d\n",T ++);
		printf("Total explored area: %.2lf \n\n",res);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值