BZOJ 2752: [HAOI2012]高速公路(road) (线段树) - Gemini Boy - ACM之路~

BZOJ 2752: [HAOI2012]高速公路(road) (线段树)

Gemini posted @ 2013年8月17日 05:12 in 题解 with tags 数据结构 线段树 bzoj , 1744 阅读

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2752

概率背景的题,不过稍微想想,稍微推一推,就能得到公式。然后注意到只要用线段树维护3个sum就行了,sum1 费用和, sum2 下标乘以费用的和 sum3下标的平方乘以费用的和

PS:。。。在写线段树的时候被一个傻逼问题bug住了好久,,调了好久。好吧 我就是煞笔

2版线段树的代码。

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 100100;

long long sumo[maxn], sump[maxn];

struct SegNode {
	int left, right;
	long long sum1, sum2, sum3;
	long long add;

	int mid() {
		return (left + right) >> 1;
	}

	long long size() {
		return (right - left + 1);
	}
};

struct SegmentTree {

	SegNode tree[maxn*5];

	void pushUp(int idx) {
		tree[idx].sum1 = tree[idx<<1].sum1 + tree[idx<<1|1].sum1;
		tree[idx].sum2 = tree[idx<<1].sum2 + tree[idx<<1|1].sum2;
		tree[idx].sum3 = tree[idx<<1].sum3 + tree[idx<<1|1].sum3;
	}

	void pushDown(int idx) {
		if (tree[idx].add) {
			long long add = tree[idx].add;
			int right1 = tree[idx<<1].right;
			int left1 = tree[idx<<1].left;
			int right2 = tree[idx<<1|1].right;
			int left2 = tree[idx<<1|1].left;
			tree[idx].add = 0;
			tree[idx<<1].sum1 += tree[idx<<1].size() * add;
			tree[idx<<1|1].sum1 += tree[idx<<1|1].size() * add;
			tree[idx<<1].sum2 += (sumo[right1] - sumo[left1-1]) * add;
			tree[idx<<1|1].sum2 += (sumo[right2] - sumo[left2-1]) * add;
			tree[idx<<1].sum3 += (sump[right1] - sump[left1-1]) * add;
			tree[idx<<1|1].sum3 += (sump[right2] - sump[left2-1]) * add;
			tree[idx<<1].add += add;
			tree[idx<<1|1].add += add;
		}
	}

	void build(int left, int right, int idx) {
		tree[idx].left = left;
		tree[idx].right = right;
		tree[idx].sum1 = 0;
		tree[idx].sum2 = 0;
		tree[idx].sum3 = 0;
		tree[idx].add = 0;
		if (left == right)
			return ;
		int mid = tree[idx].mid();
		build(left, mid, idx<<1);
		build(mid+1, right, idx<<1|1);
	}

	void update(int left, int right, int idx, long long value) {
		if (tree[idx].left == left && tree[idx].right == right) {
			tree[idx].add += value;
			tree[idx].sum1 += tree[idx].size() * value;
			tree[idx].sum2 += (sumo[right] - sumo[left-1]) * value;
			tree[idx].sum3 += (sump[right] - sump[left-1]) * value;
			return ;
		}
		pushDown(idx);
		int mid = tree[idx].mid();
		if (right <= mid)
			update(left, right, idx<<1, value);
		else if (left > mid)
			update(left, right, idx<<1|1, value);
		else {
			update(left, mid, idx<<1, value);
			update(mid+1, right, idx<<1|1, value);
		}
		pushUp(idx);
	}

	long long query(int left, int right, int idx, int L, int R) {
		if (tree[idx].left == left && tree[idx].right == right) {
			//printf("%d %d %d\n", idx, left, right);
			return (R + L - 1) * tree[idx].sum2 - tree[idx].sum3 - 
				((long long)L * R - R) * tree[idx].sum1;
		}
		pushDown(idx);
		int mid = tree[idx].mid();
		if (right <= mid)
			return query(left, right, idx<<1, L, R);
		else if (left > mid)
			return query(left, right, idx<<1|1, L, R);
		else {
			return (query(left, mid, idx<<1, L, R) + query(mid+1, right, idx<<1|1, L, R));
		}
	}	
	
};
SegmentTree tree;

int N, M;

long long gcd(long long a, long long b) {
	return b ? gcd(b, a % b) : a;
}

void init() {
	memset(sumo, 0, sizeof(sumo));
	memset(sump, 0, sizeof(sump));
	for (int i = 1; i < maxn; i++)
		sumo[i] = sumo[i-1] + i;
	for (int i = 1; i < maxn; i++)
		sump[i] = sump[i-1] + (long long)i * i;
	scanf("%d %d", &N, &M);
	tree.build(1, N, 1);
}

void work() {
	char op[19];
	for (int i = 0; i < M; i++) {
		scanf("%s", op);
		if (op[0] == 'C') {
			int x, y;
			long long z;
			scanf("%d %d %lld", &x, &y, &z);
			tree.update(x, y-1, 1, z);
		} else {
			int x, y;
			scanf("%d %d", &x, &y);
			long long tmp = tree.query(x, y, 1, x, y);
			long long tem = (long long)(y - x + 1) * (y - x) / 2;
			long long ans = gcd(tmp, tem);
			printf("%lld/%lld\n", tmp / ans, tem / ans);
		}
	}
}

int main() {
	init();
	work();
	return 0;
}
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 100100;

long long sumo[maxn], sump[maxn];

struct SegNode {
	int left, right;
	long long sum1, sum2, sum3;
	long long add;
};

struct SegmentTree {

	SegNode tree[maxn*5];

	void pushUp(int idx) {
		tree[idx].sum1 = tree[idx<<1].sum1 + tree[idx<<1|1].sum1;
		tree[idx].sum2 = tree[idx<<1].sum2 + tree[idx<<1|1].sum2;
		tree[idx].sum3 = tree[idx<<1].sum3 + tree[idx<<1|1].sum3;
	}

	void pushDown(int idx, int left, int right) {
		if (tree[idx].add) {
			long long add = tree[idx].add;
			tree[idx].add = 0;
			tree[idx].sum1 += (right - left + 1) * add;
			tree[idx].sum2 += (sumo[right] - sumo[left-1]) * add;
			tree[idx].sum3 += (sump[right] - sump[left-1]) * add;
			if (left == right) return ;
			tree[idx<<1].add += add;
			tree[idx<<1|1].add += add;
		}
	}

	void update(int L, int R, int left, int right, int idx, long long value) {
		pushDown(idx, L, R);
		if (L >= left && R <= right) {
			tree[idx].add += value;
			return ;
		}
		int mid = (L + R) >> 1;
		if (left <= mid)
			update(L, mid, left, right, idx<<1, value);
		if (right >= mid+1)
			update(mid+1, R, left, right, idx<<1|1, value);
		pushDown(idx<<1, L, mid);
		pushDown(idx<<1|1, mid+1, R);
		pushUp(idx);
	}

	long long query(int L, int R, int left, int right, int idx) {
		pushDown(idx, L, R);
		if (L >= left && R <= right) {
			printf("%d %d %d\n", idx, left, right);
			return (right + left - 1) * tree[idx].sum2 - tree[idx].sum3 - 
				((long long)left * right - right) * tree[idx].sum1;
		}
		int mid = (L + R) >> 1;
		long long ans = 0;
		if (left <= mid)
			ans += query(L, mid, left, right, idx<<1);
		if (right >= mid + 1)
			ans += query(mid+1, R, left, right, idx<<1|1);
		return ans;
	}		
	
};
SegmentTree tree;

int N, M;

long long gcd(long long a, long long b) {
	return b ? gcd(b, a % b) : a;
}

void init() {
	memset(sumo, 0, sizeof(sumo));
	memset(sump, 0, sizeof(sump));
	for (int i = 1; i < maxn; i++)
		sumo[i] = sumo[i-1] + i;
	for (int i = 1; i < maxn; i++)
		sump[i] = sump[i-1] + (long long)i * i;
	scanf("%d %d", &N, &M);
}

void work() {
	char op[19];
	for (int i = 0; i < M; i++) {
		scanf("%s", op);
		if (op[0] == 'C') {
			int x, y;
			long long z;
			scanf("%d %d %lld", &x, &y, &z);
			tree.update(1, N, x, y-1, 1, z);
		} else {
			int x, y;
			scanf("%d %d", &x, &y);
			long long tmp = tree.query(1, N, x, y, 1);
			long long tem = (long long)(y - x + 1) * (y - x) / 2;
			long long ans = gcd(tmp, tem);
			printf("%lld/%lld\n\n", tmp / ans, tem / ans);
		}
	}
}

int main() {
	init();
	work();
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter
Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee