UOJ46 【清华集训2014】玄学 【时间线段树】

题目链接:UOJ

这题的时间线段树非常的妙。

对时间建立线段树,修改的时候在后面加,每当填满一个节点之后就合并进它的父亲。

对于一个节点维护序列,发现这是一个分段函数,合并就是归并排序。于是就形成了差不多这样的一个结构。

无标题

查询的时候在分段函数上二分。

因为每个断点至多被合并(log n)次,所以时间复杂度是(O(nlog^2n+mlog n))

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef long long LL;
const int N = 100003;
int id, tot, n, m, mod, val[N];
struct Node {
	int a, b, r;
	inline Node(int _a = 0, int _b = 0, int _r = 0): a(_a), b(_b), r(_r){}
	inline Node operator * (const Node &o) const {
		return Node((LL) a * o.a % mod, ((LL) b * o.a + o.b) % mod, min(r, o.r));
	}
	inline bool operator < (const Node &o) const {
		if(r != o.r) return r < o.r;
		if(a != o.a) return a < o.a;
		return b < o.b;
	}
};
vector<Node> seg[N << 2];
inline void add(int x, int l, int r, int a, int b){
	seg[x].push_back(Node(1, 0, l - 1)); seg[x].push_back(Node(a, b, r)); if(r < n) seg[x].push_back(Node(1, 0, n));
}
inline void merge(vector<Node> &res, const vector<Node> A, const vector<Node> B){
	int p = 0, q = 0;
	while(p < A.size() && q < B.size()){
		res.push_back(A[p] * B[q]);
		if(A[p].r == B[q].r) ++ p, ++ q;
		else if(A[p].r < B[q].r) ++ p;
		else ++ q;
	}
}
inline void change(int x, int L, int R, int l, int r, int a, int b){
	if(L == R){add(x, l, r, a, b); return;}
	int mid = L + R >> 1;
	if(tot <= mid) change(x << 1, L, mid, l, r, a, b);
	else change(x << 1 | 1, mid + 1, R, l, r, a, b);
	if(tot == R) merge(seg[x], seg[x << 1], seg[x << 1 | 1]);
}
int ans;
inline void query(int x, int L, int R, int l, int r, int k){
	if(l <= L && R <= r){
		auto it = lower_bound(seg[x].begin(), seg[x].end(), Node(0, 0, k));
		ans = ((LL) ans * (it -> a) + (it -> b)) % mod;
		return;
	}
	int mid = L + R >> 1;
	if(l <= mid) query(x << 1, L, mid, l, r, k);
	if(mid < r) query(x << 1 | 1, mid + 1, R, l, r, k);
}
int main(){
	scanf("%d%d%d", &id, &n, &mod);
	for(Rint i = 1;i <= n;i ++)
		scanf("%d", val + i);
	scanf("%d", &m);
	for(Rint i = 1;i <= m;i ++){
		int opt, l, r, a, b;
		scanf("%d%d%d%d", &opt, &l, &r, &a);
		if(id & 1) l ^= ans, r ^= ans;
		if(opt == 1){
			scanf("%d", &b); ++ tot;
			change(1, 1, n, l, r, a, b);
		} else if(opt == 2){
			if(id & 1) a ^= ans;
			ans = val[a];
			query(1, 1, n, l, r, a);
			printf("%d
", ans);
		}
	}
}
原文地址:https://www.cnblogs.com/AThousandMoons/p/11733197.html