zoukankan      html  css  js  c++  java
  • P4315 月下毛景树 (树链剖分)

    P4315 月下毛景树

    补题地址

    这是一道树剖(线段树)好题 。思路就是树链剖分,然后线段树维护最值。 这道题麻烦在两点:

    • 边权转点权
    • 区间加 + 区间覆盖的 lazy 标记处理 (要强调本线段树维护最值)

    首先边权转点权处理,其实如果做过 P3038 那边权转点权并不是什么大问题,只要把点 x 和父亲结点相连的边的权值看成点 x 的权值就行了。 同时注意各种操作时处理(dfn[x] + 1)(dfn[y]) 就行了。

    主要看第二个问题的处理,如果只有一个的话就不难,但两个的话就需要两个lazy标记:(lz1:) 区间覆盖标记,(lz2:) 区间加标记。我没们在pushdown时,要先处理区间覆盖的lazy标记:

    if(tree[index].lz1 >= 0){
       //覆盖后那子区间最值就是lz1
       tree[index << 1].val = tree[index << 1 | 1].val = tree[index].lz1;
       //子区间最值也是lz1,这里下传标记
       tree[index << 1].lz1 = tree[index << 1 | 1].lz1 = tree[index].lz1;
       //子区间加的标记是之前下传的,现在覆盖了就要改为0
       tree[index << 1].lz2 = tree[index << 1 | 1].lz2 = 0;
       //当前区间标记已经使用所有初始化
       tree[index].lz1 = -1;
    }
    

    再处理区间加的lazy标记:

    if(tree[index].lz2){
        //由于区间加,子区间最值也+val
        tree[index << 1].val += tree[index].lz2; 
        tree[index << 1 | 1].val +=tree[index].lz2;
        //下传lz2标记
        tree[index << 1].lz2 += tree[index].lz2; 
        tree[index << 1 | 1].lz2 += tree[index].lz2;
        //使用后标记初始化
        tree[index].lz2  = 0;
    }
    

    然后其他线段树部分维护区间最值。


    Change:

    void Change(int x, int val){
        updata1(dfn[x], dfn[x], 1, val);
    }
    

    Cover:

    void Cover(int x, int y, int val){
        while(top[x] != top[y]){
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            updata1(dfn[top[x]], dfn[x], 1, val);
            x = fa[top[x]];
        }
        if(dep[x] > dep[y]) swap(x, y);
        updata1(dfn[x] + 1, dfn[y], 1, val);	//边权转点权后注意这里
    }
    

    Add:

    void Add(int x, int y, int val){
        while(top[x] != top[y]){
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            updata2(dfn[top[x]], dfn[x], 1, val);
            x = fa[top[x]];
        }
        if(dep[x] > dep[y]) swap(x, y);
        updata2(dfn[x] + 1, dfn[y], 1, val);	//边权转点权后注意这里
    }
    

    Max:

    int Max(int x, int y){
        int ans = 0;
        while(top[x] != top[y]){
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            ans = max(ans, query(dfn[top[x]], dfn[x], 1));
            x = fa[top[x]];
        }
        if(dep[x] > dep[y]) swap(x, y);
        ans = max(ans, query(dfn[x] + 1, dfn[y], 1));	//边权转点权后注意这里
        return ans;
    }
    

    代码:

    /*
    2020/8/17/19:59
    树链剖分:含点权转边权处理。
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, n) for(int i = a; i <= n; ++ i);
    #define per(i, a, n) for(int i = n; i >= a; -- i);
    typedef long long ll;
    const int N = 2e6+ 5;
    const ll mod = 1e9 + 7;
    const double Pi = acos(- 1.0);
    const int INF = 0x3f3f3f3f;
    const int G = 3, Gi = 332748118;
    ll qpow(ll a, ll b) { ll res = 1; while(b){ if(b & 1) res = (res * a) % mod; a = (a * a) % mod; b >>= 1;} return res; }
    ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
    ll lcm(ll a, ll b) { return a * b / gcd(a, b);}
    bool cmp(int a, int b){ return a > b;}
    //
    int tpp[N];
    
    int n, m;
    
    int ax[N], ay[N];
    int head[N], cnt = 0, tot = 0;
    int siz[N], dep[N], fa[N], son[N];
    int dfn[N], tval[N], val[N], top[N], rnk[N];
    
    struct node{
        int to, nxt, c;
    }edge[N << 1];
    
    void add(int u, int v, int w){
        edge[cnt].to = v, edge[cnt].c = w, edge[cnt].nxt = head[u], head[u] = cnt ++;
        edge[cnt].to = u, edge[cnt].c = w, edge[cnt].nxt = head[v], head[v] = cnt ++;
    }
    
    struct Tree{
        int l, r, val;
        int lz1, lz2;
    }tree[N * 4];
    
    void pushdown(int index){
        if(tree[index].lz1 >= 0){
            tree[index << 1].val = tree[index << 1 | 1].val = tree[index].lz1;
            tree[index << 1].lz1 = tree[index << 1 | 1].lz1 = tree[index].lz1;
            tree[index << 1].lz2 = tree[index << 1 | 1].lz2 = 0;
            tree[index].lz1 = -1;
        }
        
        if(tree[index].lz2){
            tree[index << 1].val += tree[index].lz2; tree[index << 1 | 1].val += tree[index].lz2;
            tree[index << 1].lz2 += tree[index].lz2; tree[index << 1 | 1].lz2 += tree[index].lz2;
            tree[index].lz2  = 0;
        }
    }
    
    void pushup(int index){
        tree[index].val = max(tree[index << 1].val, tree[index << 1 | 1].val);
    }
    
    void Build(int l, int r, int index){
        tree[index].l = l; tree[index].r = r;
        tree[index].lz1 = -1; tree[index].lz2 = tree[index].val = 0;
        if(l == r){
            // tpp[l] = index;
            tree[index].val = tval[l];
            return;
        }
        int mid = (tree[index].l + tree[index].r) >> 1;
        Build(l, mid, index << 1);
        Build(mid + 1, r, index << 1 | 1);
        pushup(index);
    }
    
    void updata1(int l, int r, int index, int val){ 
        if(tree[index].l >= l && tree[index].r <= r){
            tree[index].lz1 = val;
            tree[index].lz2 = 0;
            tree[index].val = val;
            return;
        }
        pushdown(index);
        int mid = (tree[index].l + tree[index].r) >> 1;
        if(l <= mid) updata1(l, r, index << 1, val);
        if(r > mid) updata1(l, r, index << 1 | 1, val);
        pushup(index);
    }
    
    void updata2(int l, int r, int index, int val){
        if(tree[index].l >= l && tree[index].r <= r){
            tree[index].lz2 += val;
            tree[index].val += val;
            return;
        }
        pushdown(index);
        int mid = (tree[index].l + tree[index].r) >> 1;
        if(l <= mid) updata2(l, r, index << 1, val);
        if(r > mid) updata2(l, r, index << 1 | 1, val);
        pushup(index);
    }
    
    int query(int l, int r, int index){
        if(l <= tree[index].l && tree[index].r <= r){
            return tree[index].val;
        }
        pushdown(index);
        int mid = (tree[index].l + tree[index].r) >> 1;
        int res = 0;
        if(l <= mid) res = max(res, query(l, r, index << 1));
        if(r > mid) res = max(res, query(l, r, index << 1 | 1));
        return res;
    }
    
    //--------------------------
    void Change(int x, int val){
        updata1(dfn[x], dfn[x], 1, val);
    }
    
    void Cover(int x, int y, int val){
        while(top[x] != top[y]){
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            updata1(dfn[top[x]], dfn[x], 1, val);
            x = fa[top[x]];
        }
        if(dep[x] > dep[y]) swap(x, y);
        updata1(dfn[x] + 1, dfn[y], 1, val);
    }
    
    void Add(int x, int y, int val){
        while(top[x] != top[y]){
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            updata2(dfn[top[x]], dfn[x], 1, val);
            x = fa[top[x]];
        }
        if(dep[x] > dep[y]) swap(x, y);
        updata2(dfn[x] + 1, dfn[y], 1, val);
    }
    
    int Max(int x, int y){
        int ans = 0;
        while(top[x] != top[y]){
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            ans = max(ans, query(dfn[top[x]], dfn[x], 1));
            x = fa[top[x]];
        }
        if(dep[x] > dep[y]) swap(x, y);
        ans = max(ans, query(dfn[x] + 1, dfn[y], 1));
        return ans;
    }
    
    
    void dfs1(int u, int pre){
        dep[u] = dep[pre] + 1;
        siz[u] = 1;
        fa[u] = pre;
        int maxx = -1;
        for(int i = head[u]; i != -1; i = edge[i].nxt){
            int v = edge[i].to, w = edge[i].c;
            if(v == pre) continue;
            val[v] = w;
            dfs1(v, u);
            siz[u] += siz[v];
            if(siz[v] > maxx){
                maxx = siz[v];
                son[u] = v;
            }
        }
    }
    
    void dfs2(int u, int topu){
        dfn[u] = ++ tot;
        tval[tot] = val[u];
        top[u] = topu;
        rnk[tot] = u;
        if(!son[u]) return;
        dfs2(son[u], topu);
        for(int i = head[u]; i != -1; i = edge[i].nxt){
            int v = edge[i].to, w = edge[i].c;
            if(v == son[u] || v == fa[u]) continue;
            
            dfs2(v, v);
        }
    }
    
    // void print(){
        // for(int i = 1; i <= n; ++ i){
            // int tt = tpp[dfn[i]];
            // cout<<tree[tt].val<<" ";
        // }
        // cout<<endl;
    // }
    
    int main()
    {
        scanf("%d",&n);
        cnt = 0;
        for(int i = 0; i <= n; ++ i) head[i] = -1;
        for(int i = 1; i < n; ++ i){
            int z; scanf("%d%d%d",&ax[i], &ay[i], &z);
            add(ax[i], ay[i], z);
        }
        
        dfs1(1, 0);
        dfs2(1, 1);
        Build(1, n, 1);
        
        // print();
        
        char op[10];
        while(1){
            scanf("%s",op);
            if(op[0] == 'S') break;
            else if(op[1] == 'h'){  //change
                int x, y; scanf("%d%d",&x,&y);
                if(dep[ax[x]] < dep[ay[x]]) Change(ay[x], y);
                else Change(ax[x], y);
            }
            else if(op[1] == 'o'){ //Cover
                int x, y, z; scanf("%d%d%d",&x,&y,&z);
                Cover(x, y, z);
            }
            else if(op[1] == 'd'){   //Add
                int x, y, z; scanf("%d%d%d",&x,&y,&z);
                Add(x, y, z);
            }
            else{
                int x, y; scanf("%d%d",&x,&y);
                printf("%d
    ",Max(x, y));
            }
            // print();
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    mongodb性能测试:long时间戳与string格式时间
    .netcore mongodb 分页+模糊查询+多条件查询
    .netcore 图片处理
    ELEMENT-UI 封装el-table 局部刷新row
    vue-upload 封装组件-上传组件
    vue实现v-model父子组件间的双向通信
    cc.AudioSource
    Chrome插件:本地程序实现验证码破解(浏览器与本地进程通信)
    Chrome插件:微信公众号自动登录(chrome.extension)
    Chrome插件:浏览器后台与页面间通信
  • 原文地址:https://www.cnblogs.com/A-sc/p/13519815.html
Copyright © 2011-2022 走看看