[loj#2005][SDOI2017]相关分析 _线段树

「SDOI2017」相关分析

题目链接https://loj.ac/problem/2005


题解

把上面的式子拆掉,把下面的式子拆掉。

发现所有的东西都能用线段树暴力维护。

代码

#include <bits/stdc++.h>

#define N 100010 

#define ls p << 1

#define rs p << 1 | 1

using namespace std;

typedef double db;

typedef double ll;

ll sum[N << 2], tagx1[N << 2], tagx2[N << 2], tagy1[N << 2], tagy2[N << 2], sum2[N << 2];

bool tag1[N << 2], tag2[N << 2];

ll sumx[N << 2], sumy[N << 2];

char *p1, *p2, buf[100000];

#define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )

int rd() {
	int x = 0, f = 1;
	char c = nc();
	while (c < 48) {
		if (c == '-')
			f = -1;
		c = nc();
	}
	while (c > 47) {
		x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
	}
	return x * f;
}

inline void pushup(int p) {
	sum[p] = sum[ls] + sum[rs];
	sumx[p] = sumx[ls] + sumx[rs];
	sumy[p] = sumy[ls] + sumy[rs];
	sum2[p] = sum2[ls] + sum2[rs];
}

void pls1(int l, int r, int s, int t, int p) {
	int L = r - l + 1;
	sum[p] += (ll)t * sumx[p] + (ll)s * sumy[p] + (ll)s * t * L;
	sum2[p] += sumx[p] * s * 2 + (ll)s * s * L;
	sumx[p] += (ll)s * L;
	sumy[p] += (ll)t * L;
	if (tag2[p]) {
		tagx2[p] += s;
		tagy2[p] += t;
	}
	else {
		tagx1[p] += s;
		tagy1[p] += t;
		tag1[p] = true;
	}
}

inline ll bfr2(int x) {
	return (ll)x * (x + 1) * (2 * x + 1) / 6;
}

inline ll bfr1(int x) {
	return (ll)x * (x + 1) / 2;
}

void pls2(int l, int r, int s, int t, int p) {
	int L = r - l + 1;
	sum[p] = bfr2(r) - bfr2(l - 1) + (ll)(s + t) * (bfr1(r) - bfr1(l - 1)) + (ll)L * s * t;
	sum2[p] = bfr2(r) - bfr2(l - 1) + (ll)2 * s * (bfr1(r) - bfr1(l - 1)) + (ll)L * s * s;
	sumx[p] = bfr1(r) - bfr1(l - 1) + (ll)L * s;
	sumy[p] = bfr1(r) - bfr1(l - 1) + (ll)L * t;
	tag1[p] = false;
	tagx1[p] = tagy1[p] = 0;
	tag2[p] = true;
	tagx2[p] = s;
	tagy2[p] = t;
}

inline void pushdown(int l, int r, int p) {
	if (tag1[p]) {
		int mid = (l + r) >> 1;
		pls1(l, mid, tagx1[p], tagy1[p], ls);
		pls1(mid + 1, r, tagx1[p], tagy1[p], rs);
		tagx1[p] = tagy1[p] = 0;
		tag1[p] = false;
	}
	if (tag2[p]) {
		int mid = (l + r) >> 1;
		pls2(l, mid, tagx2[p], tagy2[p], ls);
		pls2(mid + 1, r, tagx2[p], tagy2[p], rs);
		tagx2[p] = tagy2[p] = 0;
		tag2[p] = false;
	}
}

void update1(int x, int y, int s, int t, int l, int r, int p) {
	if (x <= l && r <= y) {
		pls1(l, r, s, t, p);
		return;
	}
	int mid = (l + r) >> 1;
	pushdown(l, r, p);
	if (x <= mid) {
		update1(x, y, s, t, l, mid, ls);
	}
	if (mid < y) {
		update1(x, y, s, t, mid + 1, r, rs);
	}
	pushup(p);
}

void update2(int x, int y, int s, int t, int l, int r, int p) {
	if (x <= l && r <= y) {
		pls2(l, r, s, t, p);
		return;
	}
	int mid = (l + r) >> 1;
	pushdown(l, r, p);
	if (x <= mid) {
		update2(x, y, s, t, l, mid, ls);
	}
	if (mid < y) {
		update2(x, y, s, t, mid + 1, r, rs);
	}
	pushup(p);
}

ll queryx1(int x, int y, int l, int r, int p) {
	if (x <= l && r <= y) {
		return sumx[p];
	}
	int mid = (l + r) >> 1;
	ll ans = 0;
	pushdown(l, r, p);
	if (x <= mid) {
		ans += queryx1(x, y, l, mid, ls);
	}
	if (mid < y) {
		ans += queryx1(x, y, mid + 1, r, rs);
	}
	return ans;
}

ll queryy1(int x, int y, int l, int r, int p) {
	if (x <= l && r <= y) {
		return sumy[p];
	}
	int mid = (l + r) >> 1;
	ll ans = 0;
	pushdown(l, r, p);
	if (x <= mid) {
		ans += queryy1(x, y, l, mid, ls);
	}
	if (mid < y) {
		ans += queryy1(x, y, mid + 1, r, rs);
	}
	return ans;
}

ll query(int x, int y, int l, int r, int p) {
	if (x <= l && r <= y) {
		return sum[p];
	}
	int mid = (l + r) >> 1;
	ll ans = 0;
	pushdown(l, r, p);
	if (x <= mid) {
		ans += query(x, y, l, mid, ls);
	}
	if (mid < y) {
		ans += query(x, y, mid + 1, r, rs);
	}
	return ans;
}

ll query2(int x, int y, int l, int r, int p) {
	if (x <= l && r <= y) {
		return sum2[p];
	}
	int mid = (l + r) >> 1;
	ll ans = 0;
	pushdown(l, r, p);
	if (x <= mid) {
		ans += query2(x, y, l, mid, ls);
	}
	if (mid < y) {
		ans += query2(x, y, mid + 1, r, rs);
	}
	return ans;
}

ll a1[N], a2[N];

void build(int l, int r, int p) {
	if (l == r) {
		sum[p] = a1[l] * a2[l];
		sum2[p] = a1[l] * a1[l];
		sumx[p] = a1[l];
		sumy[p] = a2[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, ls);
	build(mid + 1, r, rs);
	pushup(p);
}

int main() {
	// freopen("gold.in", "r", stdin);
	// freopen("gold.out", "w", stdout);
	int n = rd(), Q = rd();
	for (int i = 1; i <= n; i ++ ) {
		a1[i] = rd();
	}
	for (int i = 1; i <= n; i ++ ) {
		a2[i] = rd();
	}
	build(1, n, 1);
	while (Q -- ) {
		int opt = rd();
		if (opt == 1) {
			int l = rd(), r = rd();
			db Up;
			int L = r - l + 1;
			Up = query(l, r, 1, n, 1);
			Up -= (db)queryx1(l, r, 1, n, 1) * queryy1(l, r, 1, n, 1) / L;
			db Down;
			Down = query2(l, r, 1, n, 1);
			Down -= (db)queryx1(l, r, 1, n, 1) * queryx1(l, r, 1, n, 1) / L;
			printf("%.10lf\n", Up / Down);
		}
		else if (opt == 2) {
			int l = rd(), r = rd(), s = rd(), t = rd();
			update1(l, r, s, t, 1, n, 1);
		}
		else {
			int l = rd(), r = rd(), s = rd(), t = rd();
			update2(l, r, s, t, 1, n, 1);
		}
	}
	return 0;
}

小结:对拍的时候要记得,数据尽量和题面吻合,不然容易出一些奇奇怪怪的错误。比如说这个题考试的时候,我就有个值忘记开$long\ long$,对拍没拍出来因为我保证数据非常小。

posted @ 2019-08-27 22:41 JZYshuraK_彧 阅读(...) 评论(...) 编辑 收藏