「清华集训2014」玄学-二进制分组

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/DSL_HN_2002/article/details/84989677

Description

链接

Solution

考虑对操作二进制分组。每个块内维护这个区间的操作把整个序列分成的段数(每一段有两个值 a , b a,b 代表这一段的真实值为 a x + b ax+b )。

比如相交的两个操作会形成3段,分别为 a 1 x + b a_1x+b , a 1 a 2 x + a 2 b 1 + b 2 , a 2 x + b 2 a_1a_2x+a_2b_1+b_2,a_2x+b_2

由于操作数是 O ( n ) O(n) 的,所以序列分成的段数也是 O ( n ) O(n) 的。合并时计算新的段即可。

#include <bits/stdc++.h>
using namespace std;

typedef long long lint;
const int maxn = 600005;

int T, n, mod, q;

int val[maxn], tot, id[maxn], l[maxn * 4], r[maxn * 4];

struct node
{
	int p, a, b;
} t[maxn * 30];
int cnt;

inline int gi()
{
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	int sum = 0;
	while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
	return sum;
}

#define lch (s << 1)
#define rch (s << 1 | 1)
#define mid ((l + r) >> 1)

void build(int s, int l, int r)
{
	if (l == r) return id[l] = s, void();
	build(lch, l, mid);
	build(rch, mid + 1, r);
}

void insert(int L, int R, int a, int b)
{
	++tot;
	l[id[tot]] = cnt + 1;
	if (L > 1) t[++cnt] = (node) {L - 1, 1, 0};
	t[++cnt] = (node) {R, a, b};
	if (R < n) t[++cnt] = (node) {n, 1, 0};
	r[id[tot]] = cnt;
	  
	int s = id[tot], i, j, n1, n2;
	while ((s & 1) && s > 1) {
		s >>= 1;
		l[s] = cnt + 1;
		i = l[lch]; n1 = r[lch]; j = l[rch]; n2 = r[rch];
		while (i <= n1 && j <= n2) {
			t[++cnt] = (node) {min(t[i].p, t[j].p), (lint)t[i].a * t[j].a % mod, ((lint)t[j].a * t[i].b + t[j].b) % mod};
			if (t[i].p == t[j].p) ++i, ++j;
			else if (t[i].p < t[j].p) ++i;
			else ++j;
		}
		r[s] = cnt;
	}
}

void calc(int s, int x, int &v)
{
	int L = l[s], R = r[s], Mid;
	while (L < R) {
		Mid = (L + R) >> 1;
		if (t[Mid].p >= x) R = Mid;
		else L = Mid + 1;
	}
	v = ((lint)t[L].a * v + t[L].b) % mod;
}

void query(int s, int l, int r, int x, int y, int p, int &v)
{
	if (x <= l && r <= y) return calc(s, p, v);
	if (x <= mid) query(lch, l, mid, x, y, p, v);
	if (y >= mid + 1) query(rch, mid + 1, r, x, y, p, v);
}

int main()
{
	T = gi();
	n = gi(); mod = gi();
	for (int i = 1; i <= n; ++i) val[i] = gi();
	
	q = gi();
	build(1, 1, q);

	int opt, l, r, a, b, lastans = 0;
	for (int i = 1; i <= q; ++i) {
		opt = gi();
		if (opt == 1) {
			l = gi(); r = gi(); a = gi(); b = gi();
			if (T & 1) l ^= lastans, r ^= lastans;
			insert(l, r, a, b);
		} else {
			l = gi(); r = gi(); a = gi();
			if (T & 1) l ^= lastans, r ^= lastans, a ^= lastans;
			b = val[a];
			query(1, 1, q, l, r, a, b);
			printf("%d\n", lastans = b);
		}
	}
	
	return 0;
}


猜你喜欢

转载自blog.csdn.net/DSL_HN_2002/article/details/84989677