zkw线段树 模板整理与例题

zkw线段树

目录

zkw线段树

基本知识

单点修改+区间查询

分析与代码

例题   敌兵布阵 HDU1166

例题 I Hate It HDU1754

区间加减+单点查询

分析与代码

例题 A Simple Problem with Integers HDU4267

区间最大子段和

分析与代码

例题 Can you answer these queries III HDU4027

区间修改+区间最值

分析与代码

例题 Fast Arrangement HDU3577

区间覆盖+区间求和

分析与代码

例题 Just a Hook HDU1698

敌兵布阵代码

I Hate It 代码

A Simple Problem with Integers 代码

Can you answer these queries III 代码

Fast Arrangement 代码

 Just a Hook代码



基本知识

  • 代码短
  • 常数小
  • 空间小

1) 满二叉树,自底向上

zkw线段数是建立在满二叉树上,且只能自底向上操作。

2) 闭区间转化成开区间 如:[2,6]->(1,7)

操作时需要将闭区间转化为开区间
const int M=1<<3;
L+=M-1,R+=M+1;

3) 左指针为左儿子,则包含右儿子

    右指针为右儿子,则包含左儿子
if(~L&1)ans+=T[L^1]; //   ^为取兄弟方法
if(R&1) ans+=T[R^1];

4) 左右指针互为兄弟为结束条件
if(L^R^1)break;

单点修改+区间查询

分析与代码

单点修改,向上修改

向上寻找包含的兄弟

typedef long long LL;
const int maxn = 100005;
LL T[maxn << 1];
int M = 1 << 17;
void modify(int n, LL v) {    //逐层向上,求和
	for (T[n += M] = v, n >>= 1; n; n >>= 1)
		T[n] = T[n << 1] + T[n << 1 | 1];
}
LL query(int l, int r) {
	LL ans = 0;        //逐层向上,取包含的区域
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (~l & 1) ans += T[l ^ 1];
		if (r & 1) ans += T[r ^ 1];
	}
	return ans;
}

例题   敌兵布阵 HDU1166

Add i,j-> a[i]加j

Sub i,j->a[i]减j

query i,j->i到j求和

后附代码

 

例题 I Hate It HDU1754

U i,j-> a[i]改为j

Q i j->i到j求和

后附代码

区间加减+单点查询

分析与代码

相当于lazy标记,记录加减的数

单点向上寻找和加上记录的标记

typedef long long LL;
const int maxn = 100005;
LL T[maxn << 1];
int M = 1 << 17;
void add(int l, int r) {
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (~l & 1) T[l ^ 1] += v;        //相当于lazy标记,记录加减的数
		if (r & 1) T[r ^ 1] += v;
	}
}
LL query(int n){
	LL ans = 0;        //单点向上寻找和加上记录的标记
	for (n += M; n; n >>= 1)ans += T[n];
	return ans;
}

例题 A Simple Problem with Integers HDU4267

 从a到b,每隔k,加x 如 2,6,3,4表示2,5要加4

建立多颗线段树,T【i】【j】【m】,包含所有mod(i)余j的数

每次询问一个点的值

区间最大子段和

分析与代码

最大前缀 pre,最大后缀suf,最大子段和 max,区间和 sum

使用merge函数,实现合并操作

typedef long long LL;
struct Node {
	LL pre, suf, max, sum;
}T[(M << 1) + 5],null;
Node merge(Node l, Node r) {
	Node res;
	res.sum = l.sum + r.sum;
	res.pre = max(l.pre, l.sum + r.pre);    //用右区间的前缀+左区间更新前缀
	res.suf = max(r.suf, l.suf + r.sum);    //用右区间+左区间的后缀更新后缀
	res.max = max(max(l.max,r.max), l.suf + r.pre);    //用左区间后缀+右区间前缀更新结果
	return res;
}
void modify(int n, LL v) {
	for (T[n += M] = { v,v,v,v }, n >>= 1; n; n >>= 1)
		T[n] = merge(T[n << 1], T[n << 1 | 1]);
}
LL query(int l, int r) {
	Node resL(null), resR(null);
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (~l & 1) resL = merge(resL, T[l ^ 1]);
		if (r & 1) resR = merge(T[r ^ 1], resR);
	}
	return merge(resL, resR).max;
}

例题 Can you answer these queries III HDU4027

单点修改+区间查询

区间修改+区间最值

分析与代码

void add(int L, int R, int v) {
	L += M - 1, R += M + 1;
	for (int l = L, r = R; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (~l & 1)lazy[l ^ 1] += v, T[l ^ 1] += v;    //既记录加上后的数,又记录标记
		if (r & 1)lazy[r ^ 1] += v, T[r ^ 1] += v;
	}
	L >>= 1, R >>= 1;
	for (int l = L, r = R; l; l >>= 1, r >>= 1) {
		T[l] = max(T[l << 1], T[l << 1 | 1]) + lazy[l];   //加上上层标记
		T[r] = max(T[r << 1], T[r << 1 | 1]) + lazy[r];
	}
}
int query(int l, int r) {
	int lMax = -inf, rMax = -inf;
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (lazy[l] && lMax != -inf)lMax += lazy[l];    //再加标记
		if (lazy[r] && rMax != -inf)rMax += lazy[r];
		if (~l & 1)lMax = max(lMax, T[l ^ 1]);     //先更新
		if (r & 1)rMax = max(rMax, T[r ^ 1]);
	}
	for (; l; l >>= 1, r >>= 1)
		lMax += lazy[l], rMax += lazy[r];
	return max(lMax, rMax);
}

例题 Fast Arrangement HDU3577

板子题

区间覆盖+区间求和

分析与代码

区间覆盖需要解决,无法区别标记的先后顺序问题

若1-6标记x,4-8标记y,即无法辨认6的值应该为x还是为y

需要及时更新懒惰标记,避免矛盾

typedef long long LL;
const LL inf = 1e18;
const int M = 1 << 17;
LL T[M << 1], lazy[M << 1];
void modify(int L, int R, LL v) {
	L += M - 1, R += M + 1;        更新懒惰标记,以区别标记的先后顺序问题
	for (int i = 20, l, r; i; --i) {
		l = L >> i, r = R >> i;
		if (lazy[l]) {
			lazy[l << 1] = lazy[l << 1 | 1] = lazy[l];
			T[l << 1] = T[l << 1 | 1] = lazy[l] * (1 << (i - 1));
			lazy[l] = 0;
		}
		if (lazy[r]) {
			lazy[r << 1] = lazy[r << 1 | 1] = lazy[r];
			T[r << 1] = T[r << 1 | 1] = lazy[r] * (1 << (i - 1));
			lazy[r] = 0;
		}
	}
	for (int l = L, r = R, num = 1; l > 1; l >>= 1, r >>= 1, num <<= 1) {
		if ((l ^ r ^ 1) > 1) {
			if (~l & 1)lazy[l ^ 1] = v, T[l ^ 1] = v * num;
			if (r & 1)lazy[r ^ 1] = v, T[r ^ 1] = v * num;
		}
		T[l >> 1] = T[l] + T[l ^ 1];
		T[r >> 1] = T[r] + T[r ^ 1];
	}
}
LL query(int l, int r) {
	LL ansL = 0, ansR = 0, ln = 0, rn = 0, nn = 1;
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1,nn<<=1) {
		if (lazy[l])ansL = lazy[l] * ln;
		if (lazy[r])ansR = lazy[r] * rn;
		if (~l & 1)ansL += T[l ^ 1], ln += nn;
		if (r & 1)ansR += T[r ^ 1], rn += nn;
	}
	for (; l; l >>= 1, r >>= 1) {
		if (lazy[l])ansL = lazy[l] * ln;
		if (lazy[r])ansR = lazy[r] * rn;
	}
	return ansL + ansR;
}

例题 Just a Hook HDU1698

敌兵布阵代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
#pragma warning (disable:4996)
typedef long long int LL;
const int M = 1 << 16;
LL T[M << 1];
void modify(int n, LL v) {
	for (T[n += M] = v, n >>= 1; n; n >>= 1)
		T[n] = T[n << 1] + T[n << 1 | 1];
}
LL query(int l, int r) {
	LL ans = 0;
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (~l & 1) ans += T[l ^ 1];
		if (r & 1) ans += T[r ^ 1];
	}
	return ans;
}
int main() {
	int t, g = 0;
	scanf("%d", &t);
	char s[10];
	while (t--)
	{
		printf("Case %d:\n", ++g);
		memset(T, 0, sizeof(T));
		int n;
		scanf("%d", &n);
		LL v;
		for (int i = 1; i <= n; i++)
			scanf("%lld", &v), modify(i, v);
		int i, j;
		while (~scanf("%s",s))
		{
			if (s[0] == 'Q') {
				scanf("%d%d", &i, &j);
				printf("%lld\n", query(i, j));
			}
			else if (s[0] == 'A') {
				scanf("%d%d", &i, &j);
				modify(i, T[i + M] + j);
			}
			else if (s[0] == 'S') {
				scanf("%d%d", &i, &j);
				modify(i, T[i + M] - j);
			}
			else
				break;
		}
	}
}

I Hate It 代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int M = 1 << 18;
int n, q;
LL a[M], T[M << 1];
void modify(int n, LL v) {
	for (T[n += M] = v, n >>= 1; n; n >>= 1)
		T[n] = max(T[n << 1], T[n << 1 | 1]);
}
LL query(int l, int r) {
	LL ans = 0;
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (~l & 1) ans = max(ans, T[l ^ 1]);
		if (r & 1) ans = max(ans, T[r ^ 1]);
	}
	return ans;
}
int main() {
	while (~scanf("%d%d", &n, &q)) {
		memset(T, 0, sizeof(T));
		for (int i = 1; i <= n; i++)
			scanf("%lld", &a[i]);
		for (int i = 1; i <= n; i++)
			modify(i, a[i]);
		char s[10];
		while (q--)
		{
			scanf("%s", s);
			int l, r;
			if (s[0] == 'Q') {
				scanf("%d%d", &l, &r);
				printf("%lld\n", query(l, r));
			}
			else
			{
				scanf("%d%d", &l, &r);
				modify(l, r);
			}
			/*	for (int i = 1; i <= n; i++)
					cout << T[M + i] << ' ';
				cout << '\n';*/
		}
	}
}

A Simple Problem with Integers 代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#pragma warning (disable:4996)
const int M = 1 << 16;
int T[55][M << 1];
int a[M];
void add(int i,int l, int r, int v) {
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (~l & 1) T[i][l ^ 1] += v;
		if (r & 1) T[i][r ^ 1] += v;
	}
}
int query(int i, int n) {
	int ans = 0;
	for (n += M; n; n >>= 1)ans += T[i][n];
	return ans;
}
int main() {
	int n;
	int s[11] = { 0,0,1,3,6,10,15,21,28,36,45 };
	while (~scanf("%d", &n))
	{
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		int q, g, x;
		scanf("%d", &q);
		while (q--)
		{
			scanf("%d", &g);
			if (g == 2) {
				scanf("%d", &x);
				int ans = a[x];
				for (int i = 1; i <= 10; i++)
					ans += query(s[i] + x % i, x);
				printf("%d\n", ans);
			}
			else {
				int a, b, k, c;
				scanf("%d%d%d%d", &a, &b, &k, &c);
				add(s[k] + a % k, a, b, c);
			}
		}
		memset(T, 0, sizeof(T));
	}
}

Can you answer these queries III 代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int M = 1 << 16;
const int inf = 1e9;
int n, q;
LL a[M];
struct Node {
	LL pre, suf, max, sum;
	Node(){}
	Node(LL a,LL b,LL c,LL d):pre(a),suf(b),max(c),sum(d){}
}T[(M << 1) + 5], null(-inf, -inf, -inf, -inf);
Node merge(Node l, Node r) {
	Node res;
	res.sum = l.sum + r.sum;
	res.pre = max(l.pre, l.sum + r.pre);
	res.suf = max(r.suf, l.suf + r.sum);
	res.max = max(max(l.max,r.max), l.suf + r.pre);
	return res;
}
void modify(int n, LL v) {
	for (T[n += M] = Node( v,v,v,v ), n >>= 1; n; n >>= 1)
		T[n] = merge(T[n << 1], T[n << 1 | 1]);
}
LL query(int l, int r) {
	Node resL(null), resR(null);
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (~l & 1) resL = merge(resL, T[l ^ 1]);
		if (r & 1) resR = merge(T[r ^ 1], resR);
	}
	return merge(resL, resR).max;
}
int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%lld", &a[i]);
	for (int i = 1; i <= n; i++)
		modify(i, a[i]);
	int s;
	scanf("%d", &q);
	while (q--)
	{
		scanf("%d", &s);
		int l, r;
		if (s == 1) {
			scanf("%d%d", &l, &r);
			printf("%lld\n", query(l, r));
		}
		else
		{
			scanf("%d%d", &l, &r);
			modify(l, r);
		}
	}
}

Fast Arrangement 代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const LL inf = 1e18;
const int M = 1 << 20;
LL T[M << 1], lazy[M << 1];
vector<int> E;
void add(int L, int R, LL v) {
	L += M - 1, R += M + 1;
	for (int l = L, r = R; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (~l & 1)lazy[l ^ 1] += v, T[l ^ 1] += v;
		if (r & 1)lazy[r ^ 1] += v, T[r ^ 1] += v;
	}
	L >>= 1, R >>= 1;
	for (int l = L, r = R; l; l >>= 1, r >>= 1) {
		T[l] = max(T[l << 1], T[l << 1 | 1]) + lazy[l];
		T[r] = max(T[r << 1], T[r << 1 | 1]) + lazy[r];
	}
}
LL query(int l, int r) {
	LL lMax = -inf, rMax = -inf;
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (lazy[l] && lMax != -inf)lMax += lazy[l];
		if (lazy[r] && rMax != -inf)rMax += lazy[r];
		if (~l & 1)lMax = max(lMax, T[l ^ 1]);
		if (r & 1)rMax = max(rMax, T[r ^ 1]);
	}
	for (; l; l >>= 1, r >>= 1)
		lMax += lazy[l], rMax += lazy[r];
	return max(lMax, rMax);
}
int main() {
	int t, g = 0;
	scanf("%d", &t);
	while (t--)
	{
		printf("Case %d:\n", ++g);
		E.clear();
		memset(T, 0, sizeof(T));
		memset(lazy, 0, sizeof(lazy));
		LL k, q;
		scanf("%lld%lld", &k, &q);
		LL l, r, v;
		for (int i = 1; i <= q; i++)
		{
			scanf("%lld%lld", &l, &r);
			if (query(l, r) < k) {
				E.push_back(i);
				add(l, r - 1, 1);
			}
		}
		for (int i = 0; i < E.size() - 1; i++)
			printf("%d ", E[i]);
		printf("%d \n\n", E[E.size() - 1]);
	}
}

 Just a Hook代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const LL inf = 1e18;
const int M = 1 << 20;
LL T[M << 1], lazy[M << 1];
vector<int> E;
void add(int L, int R, LL v) {
	L += M - 1, R += M + 1;
	for (int l = L, r = R; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (~l & 1)lazy[l ^ 1] += v, T[l ^ 1] += v;
		if (r & 1)lazy[r ^ 1] += v, T[r ^ 1] += v;
	}
	L >>= 1, R >>= 1;
	for (int l = L, r = R; l; l >>= 1, r >>= 1) {
		T[l] = max(T[l << 1], T[l << 1 | 1]) + lazy[l];
		T[r] = max(T[r << 1], T[r << 1 | 1]) + lazy[r];
	}
}
LL query(int l, int r) {
	LL lMax = -inf, rMax = -inf;
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (lazy[l] && lMax != -inf)lMax += lazy[l];
		if (lazy[r] && rMax != -inf)rMax += lazy[r];
		if (~l & 1)lMax = max(lMax, T[l ^ 1]);
		if (r & 1)rMax = max(rMax, T[r ^ 1]);
	}
	for (; l; l >>= 1, r >>= 1)
		lMax += lazy[l], rMax += lazy[r];
	return max(lMax, rMax);
}
int main() {
	int t, g = 0;
	scanf("%d", &t);
	while (t--)
	{
		printf("Case %d:\n", ++g);
		E.clear();
		memset(T, 0, sizeof(T));
		memset(lazy, 0, sizeof(lazy));
		LL k, q;
		scanf("%lld%lld", &k, &q);
		LL l, r, v;
		for (int i = 1; i <= q; i++)
		{
			scanf("%lld%lld", &l, &r);
			if (query(l, r) < k) {
				E.push_back(i);
				add(l, r - 1, 1);
			}
		}
		for (int i = 0; i < E.size() - 1; i++)
			printf("%d ", E[i]);
		printf("%d \n\n", E[E.size() - 1]);
	}
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值