zoukankan      html  css  js  c++  java
  • 标记永久化

    标记永久化是线段树的一个技巧,常用于无法(或难以)进行(pushdown)的较复杂的数据结构如主席树,树套树等。

    如何做?对每个节点维护(sum)(add)

    考虑修改,当询问与当前区间重合时,更新(add+=val),对所有经过的区间(sum+=valcdot (r-l+1))

    void modify(int rt, int l, int r, int L, int R, int v)
    {
    	sum[rt]+=v*(R-L+1);
    	if (l==L && r==R){add[rt]+=v; return;}
    	if (R<=mid) modify(ls, l, mid, L, R, v);
    	else if (L>mid) modify(rs, mid+1, r, L, R, v);
    	else modify(ls, l, mid, L, mid, v),
    		modify(rs, mid+1, r, mid+1, R, v);
    }
    

    考虑询问,累加经过的区间的(add),答案即为(sum_{l,r}+sum addcdot (r-l+1))

    int query(int rt, int l, int r, int L, int R, int Add)
    {
    	if (l==L && r==R) return sum[rt]+Add*(R-L+1);
    	if (R<=mid) return query(ls, l, mid, L, R, Add+add[rt]);
    	else if (L>mid) return query(rs, mid+1, r, L, R, Add+add[rt]);
    	else return query(ls, l, mid, L, mid, Add+add[rt])
    		+query(rs, mid+1, r, mid+1, R, Add+add[rt]);
    }
    

    一道模板

    普通线段树区间加(+)区间求和,可以练练手。

    #include<cstdio>
    #define int long long
    #define rep(i, a, b) for (register int i=(a); i<=(b); ++i)
    #define per(i, a, b) for (register int i=(a); i>=(b); --i)
    using namespace std;
    const int N=1000005;
    int sum[N], add[N], a[N];
    
    inline int read()
    {
     	int x=0,f=1;char ch=getchar();
        for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
        for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
        return x*f;
    }
    
    #define mid (l+r>>1)
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    
    void build(int rt, int l, int r)
    {
        if (l==r) {sum[rt]=a[l]; return;}
        build(ls, l, mid); build(rs, mid+1, r);
        sum[rt]=sum[ls]+sum[rs]; 
    }
    
    void modify(int rt, int l, int r, int L, int R, int v)
    {
        sum[rt]+=v*(R-L+1);
        if (l==L && r==R){add[rt]+=v; return;}
        if (R<=mid) modify(ls, l, mid, L, R, v);
        else if (L>mid) modify(rs, mid+1, r, L, R, v);
        else modify(ls, l, mid, L, mid, v),
            modify(rs, mid+1, r, mid+1, R, v);
    }
    
    int query(int rt, int l, int r, int L, int R, int Add)
    {
        if (l==L && r==R) return sum[rt]+Add*(R-L+1);
        if (R<=mid) return query(ls, l, mid, L, R, Add+add[rt]);
        else if (L>mid) return query(rs, mid+1, r, L, R, Add+add[rt]);
        else return query(ls, l, mid, L, mid, Add+add[rt])
            +query(rs, mid+1, r, mid+1, R, Add+add[rt]);
    }
    
    #undef mid
    #undef ls
    #undef rs
    
    signed main()
    {
        int n=read(), m=read();
        rep(i, 1, n) a[i]=read();
        build(1, 1, n);
        rep(i, 1, m)
        {
            int opt=read(), x=read(), y=read();
            if (opt==1) {int k=read(); modify(1, 1, n, x, y, k);}
            if (opt==2) printf("%lld
    ", query(1, 1, n, x, y, 0));
        }
        return 0;
    }
    
    

    一道应用

    也算是主席树上标记永久化的模板吧。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=100005;
    int rt[N], ls[N<<5], rs[N<<5], add[N<<5], tot, tim;
    long long sum[N<<5];
    
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
        for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
        return x*f;
    }
    
    int build(int rt, int l, int r)
    {
        rt=++tot; if (l==r) {scanf("%lld", &sum[rt]); return rt;}
        int mid=(l+r)>>1;
        ls[rt]=build(rt, l, mid); rs[rt]=build(rt, mid+1, r);
        sum[rt]=sum[ls[rt]]+sum[rs[rt]];
        return rt;
    }
    
    int update(int oldrt, int L, int R, int l, int r, int x)
    {
        int rt=++tot;
        ls[rt]=ls[oldrt]; rs[rt]=rs[oldrt];
        add[rt]=add[oldrt]; sum[rt]=sum[oldrt];
        sum[rt]+=1ll*(min(r, R)-max(l, L)+1)*x;
        if (l>=L && r<=R) {add[rt]+=x; return rt;}
        int mid=(l+r)>>1;
        if (L<=mid) ls[rt]=update(ls[rt], L, R, l, mid, x);
        if (R>mid) rs[rt]=update(rs[rt], L, R, mid+1, r, x);
        return rt;
    }
    
    long long query(int rt, int L, int R, int l, int r)
    {
        if (l>=L && r<=R) return sum[rt];
        long long res=1ll*(min(r, R)-max(l, L)+1)*add[rt];
        int mid=(l+r)>>1;
        if (L<=mid) res+=query(ls[rt], L, R, l, mid);
        if (R>mid) res+=query(rs[rt], L, R, mid+1, r);
        return res;
    }
    
    void clear()
    {
        tot=tim=0;
        memset(sum, 0, sizeof(sum));
        memset(rt, 0, sizeof(rt));
        memset(add, 0, sizeof(add));
    }
    
    int main()
    {
        int n, m;
        while (~scanf("%d%d", &n, &m))
        {
            clear(); rt[0]=build(0, 1, n);
            while (m--)
            {
                char opt; scanf(" %c", &opt);
                if (opt=='C') 
                {
                    int l=read(), r=read(), d=read();
                    rt[++tim]=update(rt[tim-1], l, r, 1, n, d);
                }
                if (opt=='Q')
                {
                    int l=read(), r=read();
                    printf("%lld
    ", query(rt[tim], l, r, 1, n));
                }
                if (opt=='H')
                {
                    int l=read(), r=read(), t=read();
                    printf("%lld
    ", query(rt[t], l, r, 1, n));
                }
                if (opt=='B') tim=read();
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Data Base mysql备份与恢复
    java 乱码问题解决方案
    【知识强化】第二章 物理层 2.1 通信基础
    【知识强化】第二章 进程管理 2.2 处理机调度
    【知识强化】第二章 进程管理 2.1 进程与线程
    【知识强化】第一章 操作系统概述 1.3 操作系统的运行环境
    【知识强化】第一章 网络体系结构 1.1 数据结构的基本概念
    【知识强化】第一章 网络体系结构 1.2 计算机网络体系结构与参考模型
    【知识强化】第一章 网络体系结构 1.1 计算机网络概述
    【知识强化】第一章 操作系统概述 1.1 操作系统的基本概念
  • 原文地址:https://www.cnblogs.com/ACMSN/p/10792961.html
Copyright © 2011-2022 走看看