// // // // // // // // // // // // // //

线段树 篇四(线段树维护区间最大子段和)

线段树维护区间最大子段和

前言

本身就是线段树的一种操作 单拎出来弄一个专题 例题的话就是八道 毒瘤的 \(GSS\)

还没有完成 只做了六道 后面的做完会补上

\(GSS1\)

题意

给定序列 查询给定区间中的最大子段和

思路

线段树中维护每一区间的最大前缀和 最大后缀和 区间和 并通过这些信息维护最大子段和 具体看代码

代码

/*
  Time: 4.11
  Worker: Blank_space
  Source: SP1043 GSS1 - Can you answer these queries I
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int n, m, a[B];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
namespace Seg {
	#define ls(x) x << 1
	#define rs(x) x << 1 | 1
	struct node {
		int l, r, mid, sum, max1, max2, len, lzy, ans;
		node() {l = r = mid = max1 = sum = max2 = ans = len = lzy = 0;}
		void ins(int L, int R) {l = L; r = R; mid = L + R >> 1; len = R - L + 1;}
	}t[B << 2];
	node operator + (const node &x, const node &y) {
		node z; z.l = x.l; z.r = y.r;
		z.ans = Max(Max(x.ans, y.ans), x.max2 + y.max1);
		z.max1 = Max(x.max1, x.sum + y.max1); z.max2 = Max(y.max2, y.sum + x.max2);
		z.sum = x.sum + y.sum;
		z.mid = z.l + z.r >> 1; z.len = z.r - z.l + 1;
		return z;
	}
	void build(int p, int l, int r) {
		t[p].ins(l, r); if(l == r) {t[p].ans = t[p].max1 = t[p].max2 = t[p].sum = a[l]; return ;}
		build(ls(p), l, t[p].mid); build(rs(p), t[p].mid + 1, r);
		t[p] = t[ls(p)] + t[rs(p)];
	}
	node query(int p, int l, int r) {
		if(l <= t[p].l && t[p].r <= r) return t[p];
		if(l <= t[p].mid) if(r > t[p].mid) return query(ls(p), l, r) + query(rs(p), l, r);
		else return query(ls(p), l, r); else return query(rs(p), l, r);
	}
}
/*----------------------------------------函数*/
int main() {
	n = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	Seg::build(1, 1, n); m = read();
	for(int i = 1; i <= m; i++)
	{
		int x = read(), y = read();
		printf("%d\n", Seg::query(1, x, y).ans);
	}
	return 0;
}

\(GSS2\)

题意

给定序列 查询给定区间中的最大子段和 相同的数只算一次

思路

难度完爆 \(T1\)

离线维护 将元素逐一插入 同时记录元素出现的上一个位置 插入每一个数 \(x\) 的时候 将区间 \([pre_x, i]\) 加上 \(x\) 这样就避免的一个数的重复计算 对于询问离线处理 在处理完之后的区间查询询问区间的最大子段和 答案体现为这一区间的历史最大值

代码

/*
  Time: 4.14
  Worker: Blank_space
  Source: SP1557 GSS2 - Can you answer these queries II
*/
/*--------------------------------------------*/
#include<cstdio>
#include<algorithm>
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int n, m, a[B], P[B << 1];
struct Q {int l, r, id;}q[B];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
bool cmp(Q x, Q y) {return x.r < y.r;}
namespace Seg {
	#define ls(x) x << 1
	#define rs(x) x << 1 | 1
	struct node {
		int l, r, mid, max, hmax, lzy, hlzy;
		node() {l = r = mid = max = hmax = lzy = hlzy = 0;}
		void ins(int L, int R) {l = L; r = R; mid = L + R >> 1;}
	}t[B << 2], ans[B];
	node operator + (const node &x, const node &y) {
		node z; z.l = x.l; z.r = y.r; z.mid = z.l + z.r >> 1;
		z.max = Max(x.max, y.max); z.hmax = Max(x.hmax, y.hmax);
		return z;
	}
	void build(int p, int l, int r) {
		t[p].ins(l, r); if(l == r) return ;
		build(ls(p), l, t[p].mid); build(rs(p), t[p].mid + 1, r);
	}
	void f(int p, int k, int hk) {
		t[p].hmax = Max(t[p].hmax, t[p].max + hk); t[p].max += k;
		t[p].hlzy = Max(t[p].hlzy, t[p].lzy + hk); t[p].lzy += k;
	}
	void push_down(int p) {f(ls(p), t[p].lzy, t[p].hlzy); f(rs(p), t[p].lzy, t[p].hlzy); t[p].lzy = t[p].hlzy = 0;}
	void up_date(int p, int l, int r, int k) {
		if(l <= t[p].l && t[p].r <= r) {f(p, k, k); return ;}
		push_down(p);
		if(l <= t[p].mid) up_date(ls(p), l, r, k);
		if(r > t[p].mid) up_date(rs(p), l, r, k);
		t[p] = t[ls(p)] + t[rs(p)];
	}
	node query(int p, int l, int r) {
		if(l <= t[p].l && t[p].r <= r) return t[p];
		push_down(p);
		if(l <= t[p].mid) if(r > t[p].mid) return query(ls(p), l, r) + query(rs(p), l, r);
		else return query(ls(p), l, r); else return query(rs(p), l, r);
	}
}
/*----------------------------------------函数*/
int main() {
	n = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	Seg::build(1, 1, n); m = read();
	for(int i = 1; i <= m; i++) q[i].l = read(), q[i].r = read(), q[i].id = i;
	std::sort(q + 1, q + 1 + m, cmp);
	for(int i = 1, j = 1; i <= n; i++)
	{
		Seg::up_date(1, P[a[i] + B] + 1, i, a[i]); P[a[i] + B] = i;
		while(q[j].r == i && j <= m) Seg::ans[q[j].id] = Seg::query(1, q[j].l, q[j].r), j++;
	}
	for(int i = 1; i <= m; i++) printf("%d\n", Seg::ans[i].hmax);
	return 0;
}

\(GSS3\)

题意

给定序列 支持修改 查询给定区间中的最大子段和

思路

\(1\) 的基础上加一个单点修改即可

代码

/*
  Time: 4.11
  Worker: Blank_space
  Source: SP1716 GSS3 - Can you answer these queries III
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int n, m, a[B];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
namespace Seg {
	#define ls(x) x << 1
	#define rs(x) x << 1 | 1
	struct node {
		int l, r, mid, len, max1, max2, sum, ans;
		node() {l = r = mid = len = max1 = max2 = sum = ans = 0;}
		void ins(int L, int R) {l = L; r = R; mid = L + R >> 1; len = R - L + 1;}
	}t[B << 2];
	node operator + (const node &x, const node &y) {
		node z; z.l = x.l; z.r = y.r; z.mid = z.l + z.r >> 1; z.len = z.r - z.l + 1;
		z.ans = Max(Max(x.ans, y.ans), x.max2 + y.max1);
		z.max1 = Max(x.max1, x.sum + y.max1); z.max2 = Max(y.max2, y.sum + x.max2);
		z.sum = x.sum + y.sum;
		return z;
	}
	void build(int p, int l, int r) {
		t[p].ins(l, r); if(l == r) {t[p].max1 = t[p].max2 = t[p].sum = t[p].ans = a[l]; return ;}
		build(ls(p), l, t[p].mid); build(rs(p), t[p].mid + 1, r);
		t[p] = t[ls(p)] + t[rs(p)];
	}
	void up_date(int p, int pos, int k) {
		if(t[p].l == t[p].r && t[p].l == pos) {t[p].max1 = t[p].max2 = t[p].sum = t[p].ans = k; return ;}
		if(pos <= t[p].mid) up_date(ls(p), pos, k); else up_date(rs(p), pos, k);
		t[p] = t[ls(p)] + t[rs(p)];
	}
	node query(int p, int l, int r) {
		if(l <= t[p].l && t[p].r <= r) return t[p];
		if(l <= t[p].mid) if(r > t[p].mid) return query(ls(p), l, r) + query(rs(p), l, r);
		else return query(ls(p), l, r); else return query(rs(p), l, r);
	}
}
/*----------------------------------------函数*/
int main() {
	n = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	Seg::build(1, 1, n); m = read();
	for(int i = 1; i <= m; i++)
	{
		int opt = read(), x = read(), y = read();
		if(opt == 0) Seg::up_date(1, x, y);
		if(opt == 1) printf("%d\n", Seg::query(1, x, y).ans);
	}
	return 0;
}

\(GSS4\)

题意

给定序列 区间开方 区间求和

思路

势能线段树板子

代码

/*
  Time: 4.11
  Worker: Blank_space
  Source: SP2713 GSS4 - Can you answer these queries IV
  势能线段树 
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cmath>
#define int long long
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int T, n, m, a[B], b[B], c[B], cnt;
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
namespace Seg {
	#define ls(x) x << 1
	#define rs(x) x << 1 | 1
	struct node {
		int l, r, mid, sum, max;
		node() {l = r = mid = sum = max = 0;}
		void ins(int L, int R) {l = L; r = R; mid = L + R >> 1;}
	}t[B << 2];
	node operator + (const node &x, const node &y) {
		node z; z.l = x.l; z.r = y.r; z.mid = z.l + z.r >> 1;
		z.sum = x.sum + y.sum; z.max = Max(x.max, y.max);
		return z;
	}
	void build(int p, int l, int r) {
		t[p].ins(l, r); if(l == r) {t[p].sum = t[p].max = a[l]; return ;}
		build(ls(p), l, t[p].mid); build(rs(p), t[p].mid + 1, r);
		t[p] = t[ls(p)] + t[rs(p)];
	}
	void up_date(int p, int l, int r) {
		if(l <= t[p].l && t[p].r <= r && t[p].l == t[p].r) {t[p].max = t[p].sum = std::sqrt(t[p].sum); return ;}
		if(l <= t[p].mid && t[ls(p)].max > 1) up_date(ls(p), l, r);
		if(r > t[p].mid && t[rs(p)].max > 1) up_date(rs(p), l, r);
		t[p] = t[ls(p)] + t[rs(p)];
	}
	node query(int p, int l, int r) {
		if(l <= t[p].l && t[p].r <= r) return t[p];
		if(l <= t[p].mid) if(r > t[p].mid) return query(ls(p), l, r) + query(rs(p), l, r);
		else return query(ls(p), l, r); else return query(rs(p), l, r);
	}
}
/*----------------------------------------函数*/
signed main() {
	while(~scanf("%lld", &n))
	{
		printf("Case #%lld:\n", ++T);
		for(int i = 1; i <= n; i++) a[i] = read();
		Seg::build(1, 1, n); m = read();
		for(int i = 1; i <= m; i++)
		{
			int opt = read(), x = read(), y = read(); if(x > y) Swap(x, y);
			if(opt == 0) Seg::up_date(1, x, y);
			if(opt == 1) printf("%lld\n", Seg::query(1, x, y).sum);
		}
	}
	return 0;
}

\(GSS5\)

题意

给定序列 查询左端点在区间 \([l_1, r_1]\) 中 右端点在 \([l_2, r_2]\) 中的区间最大子段和

思路

上面的板子搬过来

只考虑查询

分类讨论

  • 当区间没有重合的时候 中间的一段必选 左边取最大后缀 右边取最大前缀
  • 当区间出现重合时 分别合并 \([l_1, l_2]\)\([l_2, r2]\)\([l_1, r_1]\)\([r_1, r_2]\) 减掉重复计算的部分 特判区间 \([l_2, r_1]\) 三者取最大值

上面去重的时候计算完后再单独减 不要在区间上减 会出问题

代码

/*
  Time: 4.14
  Worker: Blank_space
  Source: SP2916 GSS5 - Can you answer these queries V
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int T, n, m, a[A];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
namespace Seg {
	#define ls(x) x << 1
	#define rs(x) x << 1 | 1
	struct node {
		int l, r, mid, sum, max, max1, max2;
		node() {l = r = mid = sum = max = max1 = max2 = 0;}
		void ins(int L, int R) {l = L; r = R; mid = L + R >> 1;}
	}t[A << 2];
	node operator + (const node &x, const node &y) {
		node z; z.l = x.l; z.r = y.r; z.mid = z.l + z.r >> 1;
		z.max1 = Max(x.max1, x.sum + y.max1); z.max2 = Max(y.max2, y.sum + x.max2);
		z.max = Max(Max(x.max, y.max), x.max2 + y.max1); z.sum = x.sum + y.sum;
		return z;
	}
	void build(int p, int l, int r) {
		t[p].ins(l, r); if(l == r) {t[p].max = t[p].sum = t[p].max1 = t[p].max2 = a[l]; return ;}
		build(ls(p), l, t[p].mid); build(rs(p), t[p].mid + 1, r);
		t[p] = t[ls(p)] + t[rs(p)];
	}
	node query(int p, int l, int r) {
		if(l > r) return t[0]; if(l <= t[p].l && t[p].r <= r) return t[p];
		if(l <= t[p].mid) if(r > t[p].mid) return query(ls(p), l, r) + query(rs(p), l, r);
		else return query(ls(p), l, r); else return query(rs(p), l, r);
	}
	int Query(int l1, int r1, int l2, int r2) {
		if(r1 < l2) return query(1, l1, r1).max2 + query(1, r1 + 1, l2 - 1).sum + query(1, l2, r2).max1;
		int res = query(1, l2, r1).max;
		if(l1 < l2) res = Max(res, query(1, l1, l2).max2 + query(1, l2, r2).max1 - a[l2]);
		if(r1 < r2) res = Max(res, query(1, l1, r1).max2 + query(1, r1, r2).max1 - a[r1]);
		return res;
	}
}
void work() {
	n = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	Seg::build(1, 1, n); m = read();
	for(int i = 1; i <= m; i++)
	{
		int l1 = read(), r1 = read(), l2 = read(), r2 = read();
		printf("%d\n", Seg::Query(l1, r1, l2, r2));
	}
}
/*----------------------------------------函数*/
int main() {
	T = read(); while(T--) work();
	return 0;
}

\(GSS6\)

没做

\(GSS7\)

题意

给定 \(n\) 个节点的树 支持路径修改与路径最大子段和查询

思路

树剖套线段树 直接摁上

链的修改与合并照常 唯一特殊的是跳到一条链上的时候 要注意链与区间的对应关系

由于合并的时候是由两端向中间合并的 有一个区间的左右是反着的 我说不太清楚 可以自己悟一下

代码

/*
  Time: 4.14
  Worker: Blank_space
  Source: SP6779 GSS7 - Can you answer these queries VII
*/
/*--------------------------------------------*/
#include<cstdio>
#include<algorithm>
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int n, m, a[B], pos[B], cnt;
struct edge {int v, nxt;}e[B << 1];
int head[B], ecnt;
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
void add_edge(int u, int v) {e[++ecnt] = (edge){v, head[u]}; head[u] = ecnt;}
namespace Seg {
	#define ls(x) x << 1
	#define rs(x) x << 1 | 1
	struct node {
		int l, r, mid, max, max1, max2, sum, len, lzy;
		node() {l = r = mid = max = max1 = max2 = sum = len = 0; lzy = INF;}
		void ins(int L, int R) {l = L; r = R; mid = L + R >> 1; len = R - L + 1;}
	}t[B << 2];
	node operator + (const node &x, const node &y) {
		node z; z.l = x.l; z.r = y.r; z.mid = z.l + z.r >> 1; z.len = z.r - z.l + 1;
		z.max = Max(Max(x.max, y.max), x.max2 + y.max1);
		z.max1 = Max(x.max1, x.sum + y.max1); z.max2 = Max(y.max2, y.sum + x.max2);
		z.sum = x.sum + y.sum;
		return z;
	}
	void build(int p, int l, int r) {
		t[p].ins(l, r); if(l == r) {t[p].sum  = a[pos[l]]; t[p].max = t[p].max1 = t[p].max2 = Max(t[p].sum, 0); return ;}
		build(ls(p), l, t[p].mid); build(rs(p), t[p].mid + 1, r);
		t[p] = t[ls(p)] + t[rs(p)];
	}
	void f(int p, int k) {t[p].sum = t[p].len * k; t[p].max = t[p].max1 = t[p].max2 = Max(t[p].sum, 0); t[p].lzy = k;}
	void push_down(int p) {f(ls(p), t[p].lzy); f(rs(p), t[p].lzy); t[p].lzy = INF;}
	void up_date(int p, int l, int r, int k) {
		if(l <= t[p].l && t[p].r <= r) {f(p, k); return ;}
		if(t[p].lzy != INF) push_down(p);
		if(l <= t[p].mid) up_date(ls(p), l, r, k);
		if(r > t[p].mid) up_date(rs(p), l, r, k);
		t[p] = t[ls(p)] + t[rs(p)];
	}
	node query(int p, int l, int r) {
		if(l <= t[p].l && t[p].r <= r) return t[p];
		if(t[p].lzy != INF) push_down(p);
		if(l <= t[p].mid) if(r > t[p].mid) return query(ls(p), l, r) + query(rs(p), l, r);
		else return query(ls(p), l, r); else return query(rs(p), l, r);
	}
}
namespace Cut {
	int siz[B], son[B], dep[B], top[B], dfn[B], fa[B];
	void dfs(int u, int pre) {
		siz[u] = 1; dep[u] = dep[pre] + 1; fa[u] = pre;
		for(int i = head[u]; i; i = e[i].nxt)
		{
			int v = e[i].v; if(v == pre) continue;
			dfs(v, u); siz[u] += siz[v];
			if(!son[u] || siz[son[u]] < siz[v]) son[u] = v;
		}
	}
	void dfs2(int u, int tp) {
		dfn[u] = ++cnt; pos[cnt] = u; top[u] = tp;
		if(!son[u]) return ; dfs2(son[u], tp);
		for(int i = head[u]; i; i = e[i].nxt)
		{
			int v = e[i].v;
			if(v == fa[u] || v == son[u]) continue;
			dfs2(v, v);
		}
	}
	void up_date(int x, int y, int k) {
		while(top[x] != top[y])
		{
			if(dep[top[x]] < dep[top[y]]) Swap(x, y);
			Seg::up_date(1, dfn[top[x]], dfn[x], k);
			x = fa[top[x]];
		}
		if(dfn[x] > dfn[y]) Swap(x, y);
		Seg::up_date(1, dfn[x], dfn[y], k);
	}
	int query(int x, int y) {
		Seg::node _x, _y;
		while(top[x] != top[y])
		{
			if(dep[top[x]] < dep[top[y]]) Swap(x, y), std::swap(_x, _y);
			_x = Seg::query(1, dfn[top[x]], dfn[x]) + _x;
			x = fa[top[x]];
		}
		if(dfn[x] > dfn[y]) std::swap(_x, _y), Swap(x, y);
		Swap(_x.max1, _x.max2); _x = _x + Seg::query(1, dfn[x], dfn[y]); _y = _x + _y;
		return _y.max;
	}
}
/*----------------------------------------函数*/
int main() {
	n = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	for(int i = 1; i < n; i++)
	{
		int x = read(), y = read();
		add_edge(x, y); add_edge(y, x);
	}
	Cut::dfs(1, 0); Cut::dfs2(1, 1); Seg::build(1, 1, cnt); m = read();
	for(int i = 1; i <= m; i++)
	{
		int opt = read(), x = read(), y = read();
		if(opt == 1) printf("%d\n", Cut::query(x, y));
		if(opt == 2) {int z = read(); Cut::up_date(x, y, z);}
	}
	return 0;
}

\(GSS8\)

没做

posted @ 2021-04-14 19:11  Blank_space  阅读(123)  评论(0编辑  收藏  举报
// // // // // // //