1. 程式人生 > 其它 >【ybtoj高效進階 21172】籌備計劃(線段樹)(樹狀陣列)

【ybtoj高效進階 21172】籌備計劃(線段樹)(樹狀陣列)

給你一個數組,然後要你支援一些操作: 給一個位置加值或者減值,詢問最優的位置,讓一段區間裡面的位置都不能是最優位置,或讓一段區間裡面的位置可以是最優位置。 最優位置是可以作為最優位置的位置中,費用最小的。 定義一個位置的費用是每個位置到它的距離乘上每個位置的權值。

籌備計劃

題目連結:ybtoj高效進階 21172

題目大意

給你一個數組,然後要你支援一些操作:
給一個位置加值或者減值,詢問最優的位置,讓一段區間裡面的位置都不能是最優位置,或讓一段區間裡面的位置可以是最優位置。
最優位置是可以作為最優位置的位置中,費用最小的。
定義一個位置的費用是每個位置到它的距離乘上每個位置的權值。

思路

考慮用資料結構維護。

首先化簡式子:\(\sum\limits_{i=1}^n(a_i|x-i|)\)
\(x\sum\limits_{i=1}^x a_i-\sum\limits_{i=1}^xa_i\times i-x\sum\limits_{i=x+1}^na_i+\sum\limits_{i=x+1}^na_i\times i\)

不難看到分成四個部分,可以用四個樹狀陣列維護。

然後至於可以不可以作為最優點,我們用線段樹來搞,那至於找位置,我們也可以直接在這個線段樹上二分。
就好惹。

程式碼

#include<cstdio>
#define ll long long 

using namespace std;

int n, q, op, x, y, re, pl;
ll maxn;
char c;

int read() {
	re = 0;
	c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') {
		re = (re << 3) + (re << 1) + c - '0';
		c = getchar();
	}
	return re;
}

void write(int x) {
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

struct SZSJ {//樹狀陣列
	ll val[200001];
	
	void insert(int x, ll va) {
		if (x <= 0) return ;
		for (; x <= n; x += x & (-x))
			val[x] += va;
	}
	
	ll query(int x) {
		ll re = 0;
		for (; x; x -= x & (-x))
			re += val[x];
		return re;
	}
}T1, T2, T3, T4;

struct XD_tree {//線段樹
	bool ckand[200001 << 2], ckor[200001 << 2];
	short lzyck[200001 << 2];
//	ll val[200001 << 2], nm[200001 << 2];
	
	void down(int now) {
		if (lzyck[now] != -1) {
			ckand[now << 1] = ckand[now << 1 | 1] = lzyck[now];
			ckor[now << 1] = ckor[now << 1 | 1] = lzyck[now];
			lzyck[now << 1] = lzyck[now << 1 | 1] = lzyck[now];
			lzyck[now] = -1;
		}
	}
	
	void col(int now, int l, int r, int L, int R, int x) {
		if (L <= l && r <= R) {
			ckand[now] = ckor[now] = x;
			lzyck[now] = x;
			return ;
		} 
		down(now);
		int mid = (l + r) >> 1;
		if (L <= mid) col(now << 1, l, mid, L, R, x);
		if (mid < R) col(now << 1 | 1, mid + 1, r, L, R, x);
		ckand[now] = ckand[now << 1] & ckand[now << 1 | 1];
		ckor[now] = ckor[now << 1] | ckor[now << 1 | 1];
	}
	
	void insert(int pl, ll va) {
		T1.insert(n - (pl - 1) + 1, va * pl);
		T2.insert(n - (pl - 1) + 1, -va);
		T3.insert(pl + 1, -va * pl);
		T4.insert(pl + 1, va); 
	}
	
	ll query(int pl) {
		return pl * (T2.query(n - pl + 1) + T4.query(pl)) + (T1.query(n - pl + 1) + T3.query(pl));
	}
	
	int get_l(int now, int l, int r, int L, int R) {
		if (l != r) down(now);
		if (L <= l && r <= R) {
			if (ckand[now]) return l;
			if (!ckor[now]) return -1;
			
			int mid = (l + r) >> 1;
			if (ckor[now << 1]) return get_l(now << 1, l, mid, L, R);
				else return get_l(now << 1 | 1, mid + 1, r, L, R); 
		}
		
		int mid = (l + r) >> 1, re = -1;
		if (L <= mid) re = get_l(now << 1, l, mid, L, R);
		if (re != -1) return re;
		if (mid < R) re = get_l(now << 1 | 1, mid + 1, r, L, R);
		return re;
	}
	
	int get_r(int now, int l, int r, int L, int R) {
		if (l != r) down(now);
		if (L <= l && r <= R) {
			if (ckand[now]) return r;
			if (!ckor[now]) return -1;
			
			int mid = (l + r) >> 1;
			if (ckor[now << 1 | 1]) return get_r(now << 1 | 1, mid + 1, r, L, R);
				else return get_r(now << 1, l, mid, L, R);
		}
		
		int mid = (l + r) >> 1, re = -1;
		if (mid < R) re = get_r(now << 1 | 1, mid + 1, r, L, R);
		if (re != -1) return re;
		if (L <= mid) re = get_r(now << 1, l, mid, L, R);
		return re;
	}
}T;

int main() {
//	freopen("position.in", "r", stdin);
//	freopen("position.out", "w", stdout);
//	freopen("read.txt", "r", stdin);
//	freopen("write.txt", "w", stdout);
	
	n = read(); q = read();
	for (int i = 1; i <= n; i++) {
		x = read();
		if (x) T.insert(i, x);
	}
	
	T.lzyck[1] = T.ckand[1] = T.ckor[1] = 1;
	int l, r;
	while (q--) {
		op = read();
		if (op == 1) {
			x = read(); y = read();
			T.insert(x, y);
		}
		if (op == 2) {
			x = read(); y = read();
			T.insert(x, -y);
		}
		if (op == 3) {
			x = read(); y = read();
			T.col(1, 1, n, x, y, 1);
		}
		if (op == 4) {
			x = read(); y = read();
			T.col(1, 1, n, x, y, 0);
		}
		
		l = 1, r = n;
		while (r - l + 1 > 2) {
			int mid = (l + r) >> 1;
			if (T.query(mid) <= T.query(mid + 1)) r = mid;
				else l = mid + 1;
		}
		maxn = 1e18; pl = -1;
		for (int i = l; i <= r; i++) {
			ll noww = T.query(i);
			if (noww < maxn) maxn = noww, pl = i;
		}
		
		l = T.get_r(1, 1, n, 1, pl); r = T.get_l(1, 1, n, pl, n);
		if (l == -1 && r == -1) {
			putchar('-'); putchar('1');
		}
		else if (l == -1 || r == -1) {
			write(l + r + 1);
		}
		else {
			if (T.query(l) <= T.query(r)) write(l);
				else write(r);
		}
		putchar('\n');
	}
	
	return 0;
}