zoukankan      html  css  js  c++  java
  • 线段树-zkw、伪动态开点、永久化标记模板

    线段树空间##

    下面“空间”是指实际维护的区间长度所占空间

    • 指针版动态开点由于 C++ 里 struct 的“对齐”操作,会额外占用内存。所以内存非常紧张的时候还是必须牺牲一点效率写数组版动态开点。
    • zkw 线段树由于必须是一颗有 (2^k) 个叶节点的满二叉树,所以需要 4 倍空间
    • 普通线段树需要 2 倍空间

    指针版伪动态开点 + 永久化标记##

    区间 max NKOJ2297 数列操作
    实际上是静态数组,动态开点只是指用到某个节点才去 p = &[++STCnt]

    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const ll INF = 1e18;
    const int _N = 110000;
    
    int N, M, STCnt;
    
    struct node {
    	ll mx, lazy;
    	node *l, *r;
    } ST[_N * 2], *Rt;
    
    void build(node *&p, int l, int r)
    {
    	if (p == NULL) p = &ST[++STCnt];
    	if (l == r) {
    		scanf("%lld", &p->mx);
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(p->l, l, mid), build(p->r, mid + 1, r);
    	p->mx = max(p->l->mx, p->r->mx);
    	return;
    }
    
    void add(node *&p, int l, int r, int s, int t, ll v)
    {
    	if (s <= l && r <= t) {
    		p->mx += v, p->lazy += v;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if (s <= mid) add(p->l, l, mid, s, t, v);
    	if (t > mid) add(p->r, mid + 1, r, s, t, v);
    	p->mx = max(p->l->mx, p->r->mx) + p->lazy;
    	return;
    }
    
    void query(node *&p, int l, int r, int s, int t, ll &v)
    {
    	if (s <= l && r <= t) {
    		v = p->mx;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	ll a = -INF, b = -INF;
    	if (s <= mid) query(p->l, l, mid, s, t, a);
    	if (t > mid) query(p->r, mid + 1, r, s, t, b);
    	v = max(a, b) + p->lazy;
    	return;
    }
    
    int main()
    {
    	scanf("%d", &N);
    	build(Rt, 1, N);
    	scanf("%d", &M);
    	while (M--) {
    		char ins[5];
    		int x, y;
    		ll z;
    		scanf("%s", ins);
    		if (ins[1] == 'D') {
    			scanf("%d%d%lld", &x, &y, &z);
    			add(Rt, 1, N, x, y, z);
    		} else {
    			scanf("%d%d", &x, &y);
    			query(Rt, 1, N, x, y, z);
    			printf("%lld
    ", z);
    		}
    	}
    	return 0;
    }
    

    zkw 线段树##

    zkw 线段树的区间修改暂时还不会,有点惨呀 OrzOrzOrz 。学是不可能学的,就只有写指针线段树再拼命卡卡常数才能维持得了生活这样子……

    NKOJ2742 【线段树】区间极大值1

    #include <stdio.h>
    #include <algorithm>
    
    using namespace std;
    
    const int INF = 1e9;
    
    int N, M, zkw;
    int A[420000];
    
    int main()
    {
    	scanf("%d%d", &N, &M);
    	
    	for (zkw = 1; zkw <= N; zkw <<= 1);
    	for (int i = 0; i <= N + 1; ++i)
    		A[zkw + i] = -INF;
    	for (int i = 1; i <= N; ++i)
    		scanf("%d", &A[zkw + i]);
    	for (int i = zkw - 1; i >= 1; --i)
    		A[i] = max(A[i << 1], A[i << 1 | 1]);
    	while (M--) {
    		int x, y, ans = -INF;
    		scanf("%d%d", &x, &y);
    		int a = zkw + x - 1, b = zkw + y + 1;
    		while (a ^ 1 ^ b) {
    			if (a & 1 ^ 1) ans = max(ans, A[a ^ 1]);
    			if (b & 1) ans = max(ans, A[b ^ 1]);
    			a >>= 1, b >>= 1;
    		}
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    

    数组版伪动态开点##

    写 struct 是因为这份代码是当时写完指针版之后改的,太懒,就是不想把 mx 改成数组。

    NKOJ2742 【线段树】区间极大值1

    #include <stdio.h>
    #include <algorithm>
    
    using namespace std;
    
    const int INF = 1e9;
    
    int N, M, Cnt, Rt, L[420000], R[420000];
    
    struct node {
    	int mx;
    	node()
    	{
    		mx = -INF;
    		return;
    	}
    } A[420000];
    
    void modify(int &p, int l, int r, int k, int d)
    {
    	if (!p) p = ++Cnt;
    	if (l == r) { A[p].mx = d; return; }
    	int mid = (l + r) >> 1;
    	if (k <= mid) modify(L[p], l, mid, k, d), A[p].mx = max(A[p].mx, A[L[p]].mx);
    	else modify(R[p], mid + 1, r, k, d), A[p].mx = max(A[p].mx, A[R[p]].mx);
    	return;
    }
    
    int query(int &p, int l, int r, int s, int t)
    {
    	if (!p) p = ++Cnt;
    	if (s <= l && r <= t) return A[p].mx;
    	int mid = (l + r) >> 1, tmp = -INF;
    	if (s <= mid && t >= l) tmp = max(tmp, query(L[p], l, mid, s, t));
    	if (s <= r && t > mid) tmp = max(tmp, query(R[p], mid + 1, r, s, t));
    	return tmp;
    }
    
    int main()
    {
    	scanf("%d%d", &N, &M);
    	
    	for (int t, i = 1; i <= N; ++i) {
    		scanf("%d", &t);
    		modify(Rt, 1, N, i, t);
    	}
    	while (M--) {
    		int x, y;
    		scanf("%d%d", &x, &y);
    		printf("%d
    ", query(Rt, 1, N, x, y));
    	}
    	return 0;
    }
    
  • 相关阅读:
    增加新分类daily——“每天学了啥?”
    gcc选项中的编译过程
    一个带路径复制的perl脚本
    git
    mysql explain 详解
    CentOS Python2.4升级到Python2.7
    mongoDb查询
    linux php 扩展
    php-redis 扩展安装
    redis Linux的安装方法
  • 原文地址:https://www.cnblogs.com/ghcred/p/9553488.html
Copyright © 2011-2022 走看看