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]);
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章