LibreOJ #6029. 「雅礼集训 2017 Day1」市场

线段树板子题。
难点在于操作 4。把 \(\lfloor\frac a d \rfloor\) 转化为 \(a - s\),其中 \(s = \lfloor\frac a d \rfloor - a\)。那么切割区间直到其中所有数对应的 \(s\) 都一样时同时减去 \(s\)

#include <cmath>
#include <cstdio>
#include <algorithm>

typedef long long ll;

const int MAXN = 1e5 + 19;

class Segment{
	private:
		struct Node{
			int l, r;
			int min, max;
			ll sum;
			int tag;
		}tr[MAXN << 2];
		
		void push_up(int node){
			tr[node].min = std::min(tr[node << 1].min, tr[node << 1 | 1].min);
			tr[node].max = std::max(tr[node << 1].max, tr[node << 1 | 1].max);
			tr[node].sum = tr[node << 1].sum + tr[node << 1 | 1].sum;
		}
		
		void push_down(int node){
			if(tr[node].tag){
				tr[node << 1].min += tr[node].tag;
				tr[node << 1].max += tr[node].tag;
				tr[node << 1].sum += (ll)tr[node].tag * (tr[node << 1].r - tr[node << 1].l + 1);
				tr[node << 1].tag += tr[node].tag;
				tr[node << 1 | 1].min += tr[node].tag;
				tr[node << 1 | 1].max += tr[node].tag;
				tr[node << 1 | 1].sum += (ll)tr[node].tag * (tr[node << 1 | 1].r - tr[node << 1 | 1].l + 1);
				tr[node << 1 | 1].tag += tr[node].tag;
				tr[node].tag = 0;
			}
		}
		
		void build(int node, int l, int r, int *w){
			tr[node].l = l, tr[node].r = r;
			if(l == r){
				tr[node].min = w[l];
				tr[node].max = w[l];
				tr[node].sum = w[l];
				tr[node].tag = 0;
				return;
			}
			int mid = (l + r) >> 1;
			build(node << 1, l, mid, w);
			build(node << 1 | 1, mid + 1, r, w);
			push_up(node);
		}
		
		int queryMin(int node, int l, int r){
			if(tr[node].l >= l && tr[node].r <= r)
				return tr[node].min;
			push_down(node);
			int mid = (tr[node].l + tr[node].r) >> 1,
				res = 0x7fffffff;
			if(l <= mid)
				res = std::min(res, queryMin(node << 1, l, r));
			if(r > mid)
				res = std::min(res, queryMin(node << 1 | 1, l, r));
			return res;
		}
		
		ll querySum(int node, int l, int r){
			if(tr[node].l >= l && tr[node].r <= r)
				return tr[node].sum;
			push_down(node);
			int mid = (tr[node].l + tr[node].r) >> 1;
			ll res = 0;
			if(l <= mid)
				res += querySum(node << 1, l, r);
			if(r > mid)
				res += querySum(node << 1 | 1, l, r);
			return res;
		}
		
		void add(int node, int l, int r, const int &val){
			if(tr[node].l >= l && tr[node].r <= r){
				tr[node].min += val;
				tr[node].max += val;
				tr[node].sum += (ll)val * (tr[node].r - tr[node].l + 1);
				tr[node].tag += val;
				return;
			}
			push_down(node);
			int mid = (tr[node].l + tr[node].r) >> 1;
			if(l <= mid)
				add(node << 1, l, r, val);
			if(r > mid)
				add(node << 1 | 1, l, r, val);
			push_up(node);
		}
		
		int div(int a, int b){
			return (int)std::floor((double)a / (double)b);
		}
		
		void subdiv(int node, const int &val){
			if(tr[node].max - div(tr[node].max, val) == tr[node].min - div(tr[node].min, val)){
				int m = div(tr[node].max, val) - tr[node].max;
				tr[node].min += m;
				tr[node].max += m;
				tr[node].sum += (ll)m * (tr[node].r - tr[node].l + 1);
				tr[node].tag += m;
				return;
			}
			push_down(node);
			subdiv(node << 1, val);
			subdiv(node << 1 | 1, val);
			push_up(node);
		}
		
		void div(int node, int l, int r, const int &val){
			if(tr[node].l >= l && tr[node].r <= r){
				subdiv(node, val);
				return;
			}
			push_down(node);
			int mid = (tr[node].l + tr[node].r) >> 1;
			if(l <= mid)
				div(node << 1, l, r, val);
			if(r > mid)
				div(node << 1 | 1, l, r, val);
			push_up(node);
		}
		
	public:
		void build(int l, int r, int *w){
			build(1, l, r, w);
		}
		
		int queryMin(int l, int r){
			return queryMin(1, l, r);
		}
		
		ll querySum(int l, int r){
			return querySum(1, l, r);
		}
		
		void add(int l, int r, const int &val){
			add(1, l, r, val);
		}
		
		void div(int l, int r, const int &val){
			div(1, l, r, val);
		}
}myTree;

int n, q;
int a[MAXN];

int main(){
	std::scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; ++i)
		std::scanf("%d", a + i);
	myTree.build(1, n, a);
	while(q--){
		int opt, l, r, c, d;
		std::scanf("%d", &opt);
		if(opt == 1){
			std::scanf("%d%d%d", &l, &r, &c);
			++l, ++r;
			myTree.add(l, r, c);
		}
		else if(opt == 2){
			std::scanf("%d%d%d", &l, &r, &d);
			++l, ++r;
			myTree.div(l, r, d);
		}
		else if(opt == 3){
			std::scanf("%d%d", &l, &r);
			++l, ++r;
			std::printf("%d\n", myTree.queryMin(l, r));
		}
		else if(opt == 4){
			std::scanf("%d%d", &l, &r);
			++l, ++r;
			std::printf("%lld\n", myTree.querySum(l, r));
		}
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/natsuka/p/market.html
今日推荐