线段树

最大数

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int m, p, t, pos = 0;
int ans = 0;
typedef long long ll;
struct segement_tree
{
	int l, r, w;
}tr[N << 2];
void push_up(int p)
{
	tr[p].w = max(tr[p << 1].w, tr[p << 1 | 1].w);
	return ;
}
void update (int p, int l, int r, int x, int val)
{
	if(l == r) 
	{
		tr[p].w = val;
		return ;
	}
	int mid = l + r >> 1;
	if(x <= mid) update(p << 1, l, mid, x, val);
	else update(p << 1 | 1, mid + 1, r, x, val);
	push_up(p);
	return ;
}
int query(int p, int l, int r, int L, int R)
{
	if(L <= l && r <= R) return tr[p].w;
	if(l > R || r < L) return 0;
	int mid = l + r >> 1;
	return max(query(p << 1, l, mid, L, R), query(p << 1 | 1, mid + 1, r, L, R));
}
int main()
{
	scanf("%d %d", &m, &p);
	char s[2];
	while(m --)
	{
		scanf("%s %d", s, &t);
		if(s[0] == 'A') 
		{
			t = ((ll)t + ans) % p, pos ++;
			update(1, 1, N - 5, pos, t);
		}
		else if(s[0] == 'Q') ans = query(1, 1, N - 5, pos - t + 1, pos), printf("%d\n", ans);
	}
	return 0;
}

你能回答这些问题吗

build_tree函数里面记得push_up一下

#include <bits/stdc++.h>
using namespace std;
const int N = 500005, inf = 200000000;
int n, m, a[N];
struct segement_tree
{
	int lw, rw, w, sum;
}tr[N << 2];
segement_tree push_up(segement_tree x, segement_tree y)
{
	segement_tree t;
	t.lw = max(x.lw,  x.sum + y.lw);
	t.rw = max(y.rw, y.sum + x.rw);
	t.sum = x.sum + y.sum;
	t.w = max(max(x.w, y.w), x.rw + y.lw);
	return t;
}
void build_tree(int p, int l, int r)
{
	if(l == r) 
	{
		tr[p].w = tr[p].lw = tr[p].rw = tr[p].sum = a[l];
		return ;
	}
	int mid = l + r >> 1;
	build_tree(p << 1, l, mid), build_tree(p << 1 | 1, mid + 1, r);
	tr[p] = push_up(tr[p << 1], tr[p << 1 | 1]);
	return ;
}
void update(int p, int l, int r, int x, int k)
{
	if(l == r) 
	{
		tr[p].w = tr[p].lw = tr[p].rw = tr[p].sum = k;
		return ;
	}
	int mid = l + r >> 1;
	if(x <= mid) update(p << 1, l, mid, x, k);
	else update(p << 1 | 1, mid + 1, r, x, k);
	tr[p] = push_up(tr[p << 1], tr[p << 1 | 1]);
	return ;
}
segement_tree query(int p, int l, int r, int L, int R)
{
	if(L <= l && r <= R) return tr[p];
	if(l > R || r < L) return (segement_tree){-inf, -inf, -inf, 0};
	int mid = l + r >> 1;
	segement_tree a = query(p << 1, l, mid, L, R), b = query(p << 1 | 1, mid + 1, r, L, R);
	return push_up(a, b);
}
int main()
{
	scanf("%d %d", &n, &m);
	for (int i =1; i <= n; ++ i) scanf("%d", &a[i]);
	build_tree(1, 1, n);
	while(m --)
	{
		int opt, x, y;
		scanf("%d %d %d", &opt, &x, &y);
		if(opt == 2) update(1, 1, n, x, y);
		else 
		{
			if(x > y) swap(x, y);
			printf("%d\n", query(1, 1, n, x, y).w);
		}
	}
	return 0;
}

区间最大公约数

注意数组不要开小了,要是四倍。不是结构体形式的千万别忘记了。

#include <bits/stdc++.h>
using namespace std;
const int N = 500005;
typedef long long ll;
ll a[N], sum[N << 2], sm[N << 2];
int n, m;
int gcd(int x, int y)
{
	if(y == 0) return x;
	return gcd(y, x % y);
}
void push_up(int p)
{
	sum[p] = gcd(sum[p << 1], sum[p << 1 | 1]);
	sm[p] = sm[p << 1] + sm[p << 1 | 1];
	return ;
}
void build_tree(int p, int l, int r)
{
	if(l == r) 
	{
		sum[p] = a[l] - a[l - 1];
		sm[p] = sum[p];
		return ;
	}
	int mid = l + r >> 1;
	build_tree(p << 1, l, mid), build_tree(p << 1 | 1, mid + 1, r);
	push_up(p);
	return ;
}
void update(int p, int l, int r, int x, ll k)
{
	if(l == r) 
	{
		sum[p] += k;
		sm[p] += k;
		return ;
	}
	int mid = l + r >> 1;
	if(x <= mid) update(p << 1, l, mid, x, k);
	else update(p << 1 | 1, mid + 1, r, x, k);
	push_up(p);
	return ; 
}
ll query1(int p, int l, int r, int L, int R)
{
	if(L <= l && r <= R)  return sum[p];
	int mid = l + r >> 1;
	if(L <= mid && R > mid) return gcd(query1(p << 1, l, mid, L, R), query1(p << 1 | 1, mid + 1, r, L, R));
	else if(L <= mid) return query1(p << 1, l, mid, L, R);
	else return query1(p << 1 | 1, mid + 1, r, L, R); 
}
ll query2(int p, int l, int r, int L, int R)
{
	if(L <= l && r <= R) return sm[p];
	if(l > R || r < L) return 0;
	int mid = l + r >> 1;
	return query2(p << 1, l, mid, L, R) + query2(p << 1 | 1, mid + 1, r, L, R);
}
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; ++ i) scanf("%lld", &a[i]);
	build_tree(1, 1, n);
	while(m --)
	{
		char s[2];
		int l, r;
		scanf("%s %d %d", s, &l, &r);
		if(s[0] == 'Q') 
		{
			if(l == r) printf("%lld\n", query2(1, 1, n, 1, l));
			else printf("%lld\n", abs(gcd(query2(1, 1, n, 1, l), query1(1, 1, n, l + 1, r))));
		}
		else 
		{
			ll d;
			scanf("%lld", &d);
			update(1, 1, n, l, d);
			if(r <= n - 1) update(1, 1, n, r + 1, -d);
		}
	}
	return 0;
}

一个简单的整数问题2

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
typedef long long ll;
int n, lz[N << 2], m, a[N];
ll sum[N << 2];
void push_up(int p)
{
	sum[p] = sum[p << 1] + sum[p << 1 | 1];
	return ;
}
void build_tree(int p, int l, int r)
{
	if(l == r) 
	{
		sum[p] = a[l];
		return ;
	}
	int mid = l + r >> 1;
	build_tree(p << 1, l, mid), build_tree(p << 1 | 1, mid + 1, r);
	push_up(p);
	return ;
}
void push_down(int p, int l, int r)
{
	if(!lz[p]) return ;
	int mid = l + r >> 1;
	sum[p << 1] += (ll)(mid - l + 1) * lz[p];
	sum[p << 1 | 1] += (ll)(r - mid) * lz[p];
	lz[p << 1] += lz[p], lz[p << 1 | 1] += lz[p];
	lz[p] = 0;
	return ;
}
void update(int p, int l, int r, int L, int R, int d)
{
	if(L <= l && r <= R)
	{
		sum[p] = sum[p] + (ll)(r - l + 1) * d;
		lz[p] += d;
		return ;
	}
	if(l > R || r < L) return ;
	push_down(p, l, r);
	int mid = l + r >> 1;
	update(p << 1, l, mid, L, R, d);
	update(p << 1 | 1, mid + 1, r, L, R, d);
	push_up(p);
}
ll query(int p, int l, int r, int L, int R)
{
	if(L <= l && r <= R) return sum[p];
	if(l > R || r < L) return 0;
	int mid = l + r >> 1;
	push_down(p, l, r);
	return query(p << 1, l, mid, L, R) + query(p << 1 | 1, mid + 1, r, L, R);
}
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	build_tree(1, 1, n);
	while(m --)
	{
		char s[2];
		int l, r, d;
		scanf("%s", s);
		if(s[0] == 'C')
		{
			scanf("%d %d %d", &l, &r, &d);
			update(1, 1, n, l, r, d);
		}
		else
		{
			scanf("%d %d", &l, &r);
			printf("%lld\n", query(1, 1, n, l, r));
		}
	}
}

亚特兰蒂斯

垃圾题,不想用特殊性质了,直接暴力(线段树是假的)。

#include <bits/stdc++.h>
using namespace std;
typedef double db;
const int N = 40005;
db lsh[N];
int tot = 0, cnt = 0, n;
db ans = 0, pre;
struct data
{
	db x, l, r;
	int opt;
	bool operator < (const data &a) const {return x < a.x; }
}p[N];
const int inf = 0x3f3f3f3f;
int mn[N << 2], lz[N << 2];
db sum[N << 2];
void push_up(int p)
{
	mn[p] = min(mn[p << 1], mn[p << 1 | 1]);
	sum[p] = sum[p << 1] + sum[p << 1 | 1];
	return ; 
}
void push_down(int p, int l, int r)
{
	if(!lz[p]) return;
	int mid = l + r >> 1;
	mn[p << 1] += lz[p], mn[p << 1 | 1] += lz[p];
	lz[p << 1] += lz[p], lz[p << 1 | 1] += lz[p];
	lz[p] = 0;
	return ;
}
void build_tree(int p, int l, int r)
{
	lz[p] = 0;
	if(l == r) 
	{
		mn[p] = 0, sum[p] = 0;
		return ;
	}
	int mid = l + r >> 1;
	build_tree(p << 1, l, mid), build_tree(p << 1 | 1, mid + 1, r);
	push_up(p);
	return ;
}
void update(int p, int l, int r, int L, int R, int k)
{
	if(L <= l && r <= R) 
	{
		lz[p] += k;
		mn[p] += k;
		return ;
	}
	if(r < L || l > R) return ;
	int mid = l + r >> 1;
	push_down(p, l, r);
	update(p << 1, l, mid, L, R, k);
	update(p << 1 | 1, mid + 1, r, L, R, k);
	push_up(p);
}
int main()
{
	int T = 0;
	while(scanf("%d", &n) != EOF)
	{
		if(!n) break;
		cnt = tot = 0;
		T ++;
		for (int i = 1; i <= n; ++ i)
		{
			db x, y, a, b;
			scanf("%lf %lf %lf %lf", &x, &y, &a, &b);
			lsh[++ cnt] = y, lsh[++ cnt] = b;
			p[++ tot].x = x, p[tot].l = y, p[tot].r = b, p[tot].opt = 1;
			p[++ tot].x = a, p[tot].l = y, p[tot].r = b, p[tot].opt = -1;
		}
		sort(lsh + 1, lsh + cnt + 1);
		cnt = unique(lsh + 1, lsh + cnt + 1) - lsh - 1;
		sort(p + 1, p + tot + 1);
		ans = 0.0, pre = 0.0;
		build_tree(1, 1, cnt);
		for (int i = 1; i <= tot; ++ i)
		{
			int l = lower_bound(lsh + 1, lsh + cnt + 1, p[i].l) - lsh;
			int r = lower_bound(lsh + 1, lsh + cnt + 1, p[i].r) - lsh;
			if(p[i].x != p[i - 1].x) pre = query(1, 1, cnt, 1, cnt), ans = ans + pre * (p[i].x - p[i - 1].x);
			update(1, 1, cnt, l, r - 1, p[i].opt);
		}
		printf("Test case #%d\n", T);
		printf("Total explored area: %.2lf\n\n", ans);
	}
	return 0;
}

维护序列

分析:懒标记就是之前需要操作的*c+d,现在我们要在原来的基础上进行新的操作。对于一个位置x而言
x * c + d如果我们进行的是乘法操作,那么答案这个数字就会变成(x * c +d) * y = x * c * y + d * y,如果我们进行新的加法操作,这个数字就会变成x * c +d + y,我们只需要比较这两个数字和x * c +d在哪一些方面有变化就可以了。这就是先进行乘法操作的好处。

如果我们采用的形式是(x + d) * c = x * c + d * c的话,x * c + d * c+ y是无法变成一个方便的类似的形式的。

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
typedef long long ll;
int n, mod, mul[N << 2], ad[N << 2], sum[N << 2], m, a[N];
void push_up(int p)
{
	sum[p] = (ll)(sum[p << 1] + sum[p << 1 | 1]) % mod;
	return ;
} 
void push_down(int p, int l, int r)
{
	if(mul[p] == 1 && !ad[p]) return ;
	int mid = l + r >> 1;
	sum[p << 1] = ((ll)sum[p << 1] * mul[p] % mod + (ll)ad[p] * (mid - l + 1) % mod) % mod;
	sum[p << 1 | 1] = ((ll)sum[p << 1 | 1] * mul[p] % mod + (ll)ad[p] * (r - mid) % mod) % mod;
	mul[p << 1] = (ll)mul[p << 1] * mul[p] % mod;
	mul[p << 1 | 1] = (ll)mul[p << 1 | 1] * mul[p] % mod;
	ad[p << 1] = ((ll)ad[p << 1] * mul[p] % mod + ad[p]) % mod;
	ad[p << 1 | 1] = ((ll)ad[p << 1 | 1] * mul[p] % mod + ad[p]) % mod;
	ad[p] = 0, mul[p] = 1;
	return ;
}
void build_tree(int p, int l, int r)
{
	mul[p] = 1, ad[p] = 0;
	if(l == r) 
	{
		sum[p] = a[l];
		return ;
	}
	int mid = l + r >> 1;
	build_tree(p << 1, l, mid), build_tree(p << 1 | 1, mid + 1, r);
	push_up(p);
	return ;
}
void update (int p, int l, int r, int L, int R, int a, int b)
{
	if(L <= l && r <= R) 
	{
		sum[p] = ((ll)sum[p] * b % mod + (ll)a * (r - l + 1) % mod) % mod;	
		mul[p] = (ll)mul[p] * b % mod;
		ad[p] = ((ll)ad[p] * b % mod + a) % mod;
		return ;
	}	
	if(l > R || r < L) return ;
	int mid = l + r >> 1;
	push_down(p, l, r);
	update(p << 1, l, mid, L, R, a, b);
	update(p << 1 | 1, mid + 1, r, L, R, a, b);
	push_up(p);
	return ;
}
int query(int p, int l, int r, int L, int R)
{
	if(L <= l && r <= R) return sum[p];
	if(l > R || r < L) return 0;
	int mid = l + r >> 1;
	push_down(p, l, r);
	return ((ll)query(p << 1, l, mid, L, R) + query(p << 1 | 1, mid + 1, r, L, R)) % mod;
}

int main()
{
	scanf("%d %d", &n, &mod);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	build_tree(1, 1, n);
	scanf("%d", &m);
	while(m --)
	{
		int opt, t, g, c;
		scanf("%d %d %d", &opt, &t, &g);
		if(opt == 1)
		{
			scanf("%d", &c);
			update(1, 1, n, t, g, 0, c);
		}
		else if(opt == 2)
		{
			scanf("%d", &c);
			update(1, 1, n, t, g, c, 1);
		}
		else printf("%d\n", query(1, 1, n, t, g));
	}
}
posted @ 2025-02-13 10:38  Helioca  阅读(7)  评论(0)    收藏  举报
Document