Gemini Boy - ACM之路~

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

链接: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;
}

BZOJ 3251: 树上三角形

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

题意就是给一棵树,点权,然后查询一条链上是否有3个点的点权能组成一个三角形。

注意到三角形任意2边之和大于第三边,然后最坏的情况类似于斐波那契数列,大约4 50左右的时候,就会超int。所以当链的长度大于45的时候,返回true,否则就暴力判断是否可行。

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

const int maxn = 101110;

int N, Q;
vector<int> next[maxn];
long long val[maxn];
int par[maxn], dep[maxn];

void dfs(int u) {
	for (int i = 0; i < next[u].size(); i++) {
		int v = next[u][i];
		//if (dep[v]) continue;
		dep[v] = dep[u] + 1;
		dfs(v);
	}
}

bool check(int x, int y) {
	int cnt = 0;
	long long num[55];
	for ( ; dep[x] > dep[y]; x = par[x]) {
		num[cnt++] = val[x];
		if (cnt > 45) return true;
	}
	for ( ; x != y; x = par[x], y = par[y]) {
		num[cnt++] = val[x];
		num[cnt++] = val[y];
		if (cnt > 45) return true;
	}
	num[cnt++] = val[y];
	if (cnt < 3) 
		return false;
	sort(num, num + cnt);
	for (int i = 0; i + 2 < cnt; i++) {
		if (num[i] + num[i+1] > num[i+2])
			return true;
	}
	return false;
}

void init() {
	for (int i = 0; i < maxn; i++) {
		next[i].clear();
		dep[i] = 0;
		val[i] = 0;
		par[i] = 0;
	}
	par[1] = -1;
	scanf("%d %d", &N, &Q);
	for (int i = 1; i <= N; i++)
		scanf("%d", &val[i]);
	for (int i = 1; i < N; i++) {
		int x, y;
		scanf("%d %d", &x, &y);
		par[y] = x;
		next[x].push_back(y);
	}
	dep[1] = 1;
	dfs(1);
}

void work() {
	for (int i = 0; i < Q; i++) {
		int opt, x, y;
		scanf("%d %d %d", &opt, &x, &y);
		if (opt == 1)
			val[x] = y;
		else {
			if (dep[x] < dep[y])
				swap(x, y);
			if (x == y || x == par[y] || y == par[x]) {
				puts("N");
				continue;
			}
			if (check(x, y) == true)
				puts("Y");
			else puts("N");
		}
	}
}

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

BZOJ 2733: [HNOI2012]永无乡(平衡树启发式合并)

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

这题我是用treap做的,每个岛代表一个节点,每个节点维护一颗treap,然后节点之间用并查集维护,合并的时候比较俩个节点在并查集中的根的treap的节点个数,从小的向大的暴力insert进去,就行了。0.0

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <set>
using namespace std;

template <class T>  
inline void scan(T &ret) {  
    char c; ret = 0;  
    while ((c = getchar()) < '0' || c > '9')
    	;  
    while (c >= '0' && c <= '9') 
    	ret = ret * 10 + (c - '0'), c = getchar();  
}  

const int maxn = 100100;

struct TreeNode {
	TreeNode *L, *R;
	int num;
	int size;
	int pri;
	int key;
};
TreeNode nodes[maxn*30], stack[maxn*5];
TreeNode *null;
int C, Top;

void init() {
	C = 0; Top = 0;
	null = &nodes[C++];
	null->L = null->R = null;
	null->pri = -0x7FFFFFFF;
	null->size = 0;
	null->key = 0;
	null->num = 0;
}

struct Treap {

	TreeNode* root;
	vector<TreeNode*> list;

	void init() {
		root = null;
	}

	void toArrayList(TreeNode* root) {
		if (root != null) {
			toArrayList(root->L);
			list.push_back(root);
			toArrayList(root->R);
		}
	}

	TreeNode* newNode(int key, int num) {
		TreeNode* ret;
		if (Top)
			ret = &stack[--Top];
		else ret = &nodes[++C];
		ret->L = ret->R = null;
		ret->key = key;
		ret->pri = rand();
		ret->num = num;
		ret->size = num;
		return ret;
	}

	TreeNode* merge(TreeNode* small, TreeNode* large) {
		if (small == null)
			return large;
		if (large == null)
			return small;
		if (small->pri < large->pri) {
			small->R = merge(small->R, large);
			pushUp(small);
			return small;
		} else {
			large->L = merge(small, large->L);
			pushUp(large);
			return large;
		}
	}

	pair<TreeNode*, TreeNode*> split(TreeNode* root, int key) {
		pair<TreeNode*, TreeNode*> tmp;
		if (root == null) {
			tmp = make_pair(null, null);
			return tmp;
		}
		if (key <= root->key) {
			tmp = split(root->L, key);
			root->L = tmp.second;
			pushUp(root);
			tmp.second = root;
			return tmp;
		} else {
			tmp = split(root->R, key);
			root->R = tmp.first;
			pushUp(root);
			tmp.first = root;
			return tmp;
		}
	}

	TreeNode* upperBound(TreeNode* root, int key) {
		TreeNode* ans = null;
		TreeNode* i = root;
		while (i != null) {
			if (key < i->key) {
				ans = i;
				i = i->L;
			} else {
				i = i->R;
			}
		}
		return ans;
	}

	TreeNode* lowerBound(TreeNode* root, int key) {
		TreeNode* ans = null;
		TreeNode* i = root;
		while (i != null) {
			if (key < i->key) {
				i = i->L;
			} else {
				ans = i;
				i = i->R;
			}
		}
		return ans;
	}

	bool contains(TreeNode* root, int key) {
		if (root == null)
			return false;
		if (key == root->key)
			return true;
		else if (key < root->key)
			return contains(root->L, key);
		else
			return contains(root->R, key);
	}

	void insert(TreeNode* root, int key, int num) {
		if (key < root->key)
			insert(root->L, key, num);
		else if (key == root->key)
			root->num += num;
		else
			insert(root->R, key, num);
		pushUp(root);
	}

	void insert(int key, int num) {
		if (contains(root, key)) {
			insert(root, key, num);
			return ;
		}
		pair<TreeNode*, TreeNode*> tmp = split(root, key);
		TreeNode* node = newNode(key, num);
		root = merge(merge(tmp.first, node), tmp.second);
	}

	void del(int key) {
		pair<TreeNode*, TreeNode*> tmp = split(root, key);
		TreeNode* node = upperBound(tmp.second, key);
		if (node == null)
			root = tmp.first;
		else
			root = merge(tmp.first, split(tmp.second, node->key).second);
	}

	void del(TreeNode* root, int key) {
		if (!contains(root, key))
			return ;
		if (key < root->key)
			del(root->L, key);
		else if (key == root->key) {
			root->num--;
			if (root->num == 0)
				del(key);
		} else {
			del(root->R, key);
		}
		pushUp(root);
	}

	TreeNode* select(TreeNode* root, int k) {
		if (k <= root->L->size)
			return select(root->L, k);
		else if (k >= root->L->size + 1 && k <= root->L->size + root->num)
			return root;
		else 
			return select(root->R, k-root->L->size-root->num);
	}
	
	int getMin(TreeNode* root, int key) {
		if (key < root->key)
			return getMin(root->L, key);
		else if (key == root->key)
			return root->L->size + root->num;
		else
			return root->L->size + root->num + getMin(root->R, key);
	}

	int getMax(TreeNode* root, int key) {
		if (key < root->key)
			return root->R->size + root->num + getMax(root->L, key);
		else if (key == root->key)
			return root->R->size + root->num;
		else
			return getMax(root->R, key);
	}

	int size() {
		return root->size;
	}

	void visit(TreeNode* root) {
		if (root != null) {
			printf("key: %d num: %d size: %d\n", root->key, root->num, root->size);
			visit(root->L);
			visit(root->R);
		}
	}

	void pushUp(TreeNode* x) {
		x->size = x->L->size + x->R->size + x->num;
	}
};
Treap tree[maxn];

char op[10];
int n, m, q, hash[maxn], arr[maxn];
int par[maxn];

int find(int x) {
	if (par[x] != x)
		par[x] = find(par[x]);
	return par[x];
}

void merge(int x, int y) {
	int px = find(x);
	int py = find(y);
	if (px != py) {
		if (tree[px].size() < tree[py].size()) {
			par[px] = py;
			tree[px].list.clear();
			tree[px].toArrayList(tree[px].root);
			for (int i = 0; i < tree[px].list.size(); i++) {
				TreeNode* tmp = tree[px].list[i];
				tree[py].insert(tmp->key, tmp->num);
			}
		} else {
			par[py] = px;
			tree[py].list.clear();
			tree[py].toArrayList(tree[py].root);
			for (int i = 0; i < tree[py].list.size(); i++) {
				TreeNode* tmp = tree[py].list[i];
				tree[px].insert(tmp->key, tmp->num);
			}
		}
	}
}

int query(int x, int k) {
	int px = find(x);
	if (tree[px].size() < k)
		return -1;
	else 
		return tree[px].select(tree[px].root, k)->key;
}

void work() {
	init();
	scan(n); scan(m);
//	scanf("%d %d", &n, &m);
	for (int i = 0; i <= n; i++)
		tree[i].init();
	for (int i = 0; i <= n; i++)
		par[i] = i;
	for (int i = 1; i <= n; i++) {
		scan(arr[i]);
//		scanf("%d", &arr[i]);
		hash[arr[i]] = i;
	}
	for (int i = 1; i <= n; i++)
		tree[i].insert(arr[i], 1);
	for (int i = 1; i <= m; i++) {
		int x, y;
		scan(x); scan(y);
//		scanf("%d %d", &x, &y);
		merge(x, y);
	}
}

void run() {
	scanf("%d", &q);
	for (int i = 1; i <= q; i++) {
		int x, y;
		scanf("%s", op);
		scan(x); scan(y);
//		scanf("%s %d %d", op, &x, &y);
		if (op[0] == 'Q') {
			int ans = query(x, y);
			if (ans != -1)
				ans = hash[ans];
			printf("%d\n", ans);
		} else {
			merge(x, y);
		}
	}
}

int main() {
	work();
	run();
}

BZOJ 1798: [Ahoi2009]Seq 维护序列seq

http://www.lydsy.com/JudgeOnline/problem.php?id=1798

题意很简单,就是维护区间和,然后区间加一个值,区间乘以一个值。

做法就是维护 a * x + b 这个统计量,别的就是普通的线段树~

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

const int maxn = 101000;

long long value[maxn], mod;

struct SegNode {
	int left, right;
	long long sum, add, mul;

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

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

struct SegmentTree {

	SegNode tree[maxn*5];

	void pushUp(int idx) {
		tree[idx].sum = (tree[idx<<1].sum + tree[idx<<1|1].sum) % mod;
	}

	void pushDown(int idx) {
		tree[idx<<1].add = (tree[idx].mul % mod * tree[idx<<1].add % mod + tree[idx].add) % mod;
		tree[idx<<1|1].add = (tree[idx].mul % mod * tree[idx<<1|1].add % mod + tree[idx].add) % mod;
		tree[idx<<1].mul = tree[idx<<1].mul % mod * tree[idx].mul % mod;
		tree[idx<<1|1].mul = tree[idx<<1|1].mul % mod * tree[idx].mul % mod;
		tree[idx<<1].sum = (tree[idx<<1].sum % mod * tree[idx].mul % mod 
			+ tree[idx<<1].size() * tree[idx].add % mod) % mod;
		tree[idx<<1|1].sum = (tree[idx<<1|1].sum % mod * tree[idx].mul % mod 
			+ tree[idx<<1|1].size() * tree[idx].add % mod) % mod;
		tree[idx].add = 0;
		tree[idx].mul = 1;
	}

	void build(int left, int right, int idx) {
		tree[idx].left = left;
		tree[idx].right = right;
		tree[idx].sum = 0;
		tree[idx].mul = 1;
		tree[idx].add = 0;
		if (left == right) {
			tree[idx].sum = value[left] % mod;
			return ;
		}
		int mid = tree[idx].mid();
		build(left, mid, idx<<1);
		build(mid+1, right, idx<<1|1);
		pushUp(idx);
	}

	void update(int left, int right, int idx, int opt, long long val) {
		if (tree[idx].left == left && tree[idx].right == right) {
			if (opt == 1) {
				tree[idx].add = (tree[idx].add + val) % mod;
				tree[idx].sum = (tree[idx].sum + tree[idx].size() % mod * val) % mod;
			} else {
				tree[idx].add = tree[idx].add % mod * val % mod;
				tree[idx].mul = tree[idx].mul % mod * val % mod;
				tree[idx].sum = tree[idx].sum % mod * val % mod;
			}
			return ;
		}
		pushDown(idx);
		int mid = tree[idx].mid();
		if (right <= mid)
			update(left, right, idx<<1, opt, val);
		else if (left > mid)
			update(left, right, idx<<1|1, opt, val);
		else {
			update(left, mid, idx<<1, opt, val);
			update(mid+1, right, idx<<1|1, opt, val);
		}
		pushUp(idx);
	}

	long long query(int left, int right, int idx) {
		if (tree[idx].left == left && tree[idx].right == right) {
			return tree[idx].sum % mod;
		}
		pushDown(idx);
		int mid = tree[idx].mid();
		if (right <= mid)
			return query(left, right, idx<<1);
		else if (left > mid)
			return query(left, right, idx<<1|1);
		else {
			return (query(left, mid, idx<<1) % mod + query(mid+1, right, idx<<1|1));
		}
	}

};
SegmentTree tree;

int n, m;

void init() {
	scanf("%d %lld", &n, &mod);
	for (int i = 1; i <= n; i++)
		scanf("%lld", &value[i]);
	tree.build(1, n, 1);
}

void work() {
	scanf("%d", &m);
	for (int i = 1; i <= m; i++) {
		int opt, x, y;
		long long val;
		scanf("%d", &opt);
		if (opt != 3) {
			scanf("%d %d %lld", &x, &y, &val);
			tree.update(x, y, 1, 3-opt, val % mod);
		} else {
			scanf("%d %d", &x, &y);
			printf("%lld\n", tree.query(x, y, 1) % mod);
		}
	}
}

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

const int maxn = 101000;

long long value[maxn], mod;

struct SegNode {
	int left, right;
	long long sum, add, mul;
};

struct SegmentTree {
	SegNode tree[maxn*5];

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

	void pushDown(int idx, int left, int right) {
		long long add = tree[idx].add;
		long long mul = tree[idx].mul;
		tree[idx].sum = (tree[idx].sum % mod * tree[idx].mul % mod +
			(right - left + 1) * tree[idx].add % mod) % mod;
		tree[idx].add = 0;
		tree[idx].mul = 1;
		if (left == right) return ;
		tree[idx<<1].add = (mul % mod * tree[idx<<1].add % mod + add) % mod;
		tree[idx<<1|1].add = (mul % mod * tree[idx<<1|1].add % mod + add) % mod;
		tree[idx<<1].mul = tree[idx<<1].mul % mod * mul % mod;
		tree[idx<<1|1].mul = tree[idx<<1|1].mul % mod * mul % mod;
	}

	void build(int left, int right, int idx) {
		tree[idx].left = left;
		tree[idx].right = right;
		tree[idx].sum = 0;
		tree[idx].mul = 1;
		tree[idx].add = 0;
		if (left == right) {
			tree[idx].sum = value[left] % mod;
			return ;
		}
		int mid = (tree[idx].right + tree[idx].left) >> 1;
		build(left, mid, idx<<1);
		build(mid+1, right, idx<<1|1);
		pushUp(idx);
	}

	void update(int L, int R, int left, int right, int idx, int opt, long long value) {
		pushDown(idx, L, R);
		if (L >= left && R <= right) {
			if (opt == 1) {
				tree[idx].add = (tree[idx].add + value) % mod;
			} else {
				tree[idx].add = tree[idx].add % mod * value % mod;
				tree[idx].mul = tree[idx].mul % mod * value % mod;
			}
			return ;
		}
		int mid = (L + R) >> 1;
		if (left <= mid)
			update(L, mid, left, right, idx<<1, opt, value);
		if (right >= mid+1)
			update(mid+1, R, left, right, idx<<1|1, opt, 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) {
			return tree[idx].sum % mod;
		}
		int mid = (L + R) >> 1;
		long long ans = 0;
		if (left <= mid)
			ans = (ans + query(L, mid, left, right, idx<<1)) % mod;
		if (right >= mid + 1)
			ans = (ans + query(mid+1, R, left, right, idx<<1|1)) % mod;
		return ans;
	}
};

SegmentTree tree;

int n, m;

void init() {
	scanf("%d %lld", &n, &mod);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &value[i]);
	}
	tree.build(1, n, 1);
}

void work() {
	scanf("%d", &m);
	for (int i = 1; i <= m; i++) {
		int opt, x, y;
		long long val;
		scanf("%d", &opt);
		if (opt != 3) {
			scanf("%d %d %lld", &x, &y, &val);
			tree.update(1, n, x, y, 1, 3-opt, val % mod);
		} else {
			scanf("%d %d", &x, &y);
			printf("%lld\n", tree.query(1, n, x, y, 1) % mod);
		}
	}
}

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

HDU 4578:http://acm.hdu.edu.cn/showproblem.php?pid=4578

这里还有道加强版,维护区间1次方和,2次方和,3次方和,区间加一个数,乘一个数,赋值。

更新的做法类似,要注意特殊处理赋值操作,赋值操作相当于a=1,b=0。

然后对于查询,其实2次方和,3次方和都可以展开来搞~

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

const int maxn = 100100;
const int mod = 10007;

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

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

	int 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) % mod;
		tree[idx].sum2 = (tree[idx<<1].sum2 + tree[idx<<1|1].sum2) % mod;
		tree[idx].sum3 = (tree[idx<<1].sum3 + tree[idx<<1|1].sum3) % mod;
	}

	void pushDown(int idx) {
		if (tree[idx].set != 0) {
			int set1 = tree[idx].set % mod;
			int set2 = set1 % mod * set1 % mod;
			int set3 = set2 % mod * set1 % mod;
			tree[idx<<1].set = set1;
			tree[idx<<1|1].set = set1;
			tree[idx<<1].add = 0;
			tree[idx<<1|1].add = 0;
			tree[idx<<1].mul = 1;
			tree[idx<<1|1].mul = 1;
			tree[idx<<1].sum1 = tree[idx<<1].size() * set1 % mod;
			tree[idx<<1|1].sum1 = tree[idx<<1|1].size() * set1 % mod;
			tree[idx<<1].sum2 = tree[idx<<1].size() * set2 % mod;
			tree[idx<<1|1].sum2 = tree[idx<<1|1].size() * set2 % mod;
			tree[idx<<1].sum3 = tree[idx<<1].size() * set3 % mod;
			tree[idx<<1|1].sum3 = tree[idx<<1|1].size() * set3 % mod;
			tree[idx].set = 0;
		} 
		int mul1 = tree[idx].mul % mod;
		int mul2 = mul1 % mod * mul1 % mod;
		int mul3 = mul2 % mod * mul1 % mod;
		int add1 = tree[idx].add % mod;
		int add2 = add1 % mod * add1 % mod;
		int add3 = add2 % mod * add1 % mod;
		tree[idx<<1].add = (tree[idx].mul % mod * tree[idx<<1].add % mod 
			+ tree[idx].add) % mod;
		tree[idx<<1|1].add = (tree[idx].mul % mod * tree[idx<<1|1].add % mod 
			+ tree[idx].add) % mod;
		tree[idx<<1].mul = tree[idx<<1].mul % mod * tree[idx].mul % mod;
		tree[idx<<1|1].mul = tree[idx<<1|1].mul % mod * tree[idx].mul % mod;
		int sum1 = tree[idx<<1].sum1;
		int sum2 = tree[idx<<1].sum2;
		int sum3 = tree[idx<<1].sum3;
		int size = tree[idx<<1].size();
		tree[idx<<1].sum1 = (sum1 % mod * mul1 % mod 
			+ size % mod * add1 % mod) % mod;
		tree[idx<<1].sum2 = (sum2 % mod * mul2 % mod 
			+ 2 * add1 % mod * mul1 % mod * sum1 % mod + size % mod * add2 % mod) % mod;
		tree[idx<<1].sum3 = (mul3%mod*sum3%mod + 3*mul2%mod*add1%mod*sum2%mod 
			+ 3*mul1%mod*add2%mod*sum1%mod + size%mod*add3%mod) % mod;
		sum1 = tree[idx<<1|1].sum1;
		sum2 = tree[idx<<1|1].sum2;
		sum3 = tree[idx<<1|1].sum3;
		size = tree[idx<<1|1].size();
		tree[idx<<1|1].sum1 = (sum1 % mod * mul1 % mod 
			+ size % mod * add1  % mod) % mod;
		tree[idx<<1|1].sum2 = (sum2 % mod * mul2 % mod 
			+ 2 * add1 % mod * mul1 % mod * sum1 % mod + size % mod * add2 % mod) % mod;
		tree[idx<<1|1].sum3 = (mul3%mod*sum3%mod + 3*mul2%mod*add1%mod*sum2%mod 
			+ 3*mul1%mod*add2%mod*sum1%mod + size%mod*add3%mod) % mod;
		tree[idx].add = 0;
		tree[idx].mul = 1;
	}

	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].set = 0;
		tree[idx].mul = 1;
		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);
		pushUp(idx);
	}

	void update(int left, int right, int idx, int opt, int val) {
		if (tree[idx].left == left && tree[idx].right == right) {
			int val1 = val % mod;
			int val2 = val1 % mod * val1 % mod;
			int val3 = val2 % mod * val1 % mod;
			int sum1 = tree[idx].sum1;
			int sum2 = tree[idx].sum2;
			int sum3 = tree[idx].sum3;
			int size = tree[idx].size();
			if (opt == 1) {
				tree[idx].add = (tree[idx].add + val1 % mod) % mod;
				tree[idx].sum1 = (sum1 + size * val1 % mod) % mod;
				tree[idx].sum2 = (sum2 + 2 * sum1 % mod * val1 % mod 
					+ size % mod * val2 % mod) % mod;
				tree[idx].sum3 = (sum3 + 3 * sum2 % mod * val1 % mod 
					+ 3 * sum1 % mod * val2 % mod + size % mod * val3 % mod) % mod;
			} else if (opt == 2) {
				tree[idx].add = tree[idx].add * val1 % mod;
				tree[idx].mul = tree[idx].mul * val1 % mod;
				tree[idx].sum1 = sum1 % mod * val1 % mod;
				tree[idx].sum2 = sum2 % mod * val2 % mod;
				tree[idx].sum3 = sum3 % mod * val3 % mod;
			} else {
				tree[idx].add = 0;
				tree[idx].mul = 1;
				tree[idx].set = val1;
				tree[idx].sum1 = size % mod * val1 % mod;
				tree[idx].sum2 = size % mod * val2 % mod;
				tree[idx].sum3 = size % mod * val3 % mod;
			}
			return ;
		}
		pushDown(idx);
		int mid = tree[idx].mid();
		if (right <= mid)
			update(left, right, idx<<1, opt, val);
		else if (left > mid)
			update(left, right, idx<<1|1, opt, val);
		else {
			update(left, mid, idx<<1, opt, val);
			update(mid+1, right, idx<<1|1, opt, val);
		}
		pushUp(idx);
	}

	int query(int left, int right, int idx, int opt) {
		if (tree[idx].left == left && tree[idx].right == right) {
			if (opt == 1)
				return tree[idx].sum1;
			else if (opt == 2)
				return tree[idx].sum2;
			else
				return tree[idx].sum3;
		}
		pushDown(idx);
		int mid = tree[idx].mid();
		if (right <= mid)
			return query(left, right, idx<<1, opt);
		else if (left > mid)
			return query(left, right, idx<<1|1, opt);
		else {
			return (query(left, mid, idx<<1, opt) % mod + query(mid+1, right, idx<<1|1, opt)) % mod;
		}
	}
};

SegmentTree tree;

int N, M;

void work() {
	tree.build(1, N, 1);
	int x, y, val, opt;
	for (int i = 0; i < M; i++) {
		scanf("%d %d %d %d", &opt, &x, &y, &val);
		if (opt == 4)
			printf("%d\n", tree.query(x, y, 1, val));
		else
			tree.update(x, y, 1, opt, val);
	}
}

int main() {
	while (scanf("%d %d", &N, &M) != EOF) {
		if (N == 0 && M == 0) 
			break;
		work();
	}
}




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee