zoukankan      html  css  js  c++  java
  • BZOJ2157 边转点 树链剖分

    https://www.lydsy.com/JudgeOnline/problem.php?id=2157

    现在就是后悔,非常后悔

    本来想随便拿个树剖热身,不料开了个毒瘤题。

    题意:动态维护一棵树上的链最大值,最小值,和,修改的操作是一条链全部取反以及一条边单点修改

     

    边转点是肯定要边转点的,把所有的边化成两端深度更深的那个点的权值,然后直接上树剖化成线段树

    线段树就是很常规的最大小值还有和,单点修改就直接改,区间修改就打lazy标记,对于一个区间的取反操作,和直接取反,最大小值互换之后取反。

    问题在于对树链u,v操作的时候,lca(u,v)这个点是不可以算进去的,因为边转点的特性这个点不属于这条树链,所以考虑对u到lca和v到lca这两条树链分别操作,这样lca这个点就是需要查询(修改)的序列的端点,在操作的时候手动 + 1把这个点忽略掉就可以。

     

    整体感觉不难,唯一的毒瘤点在于写起来很麻烦

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
    while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
    const double eps = 1e-9;
    const int maxn = 20010;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,K;
    struct Edge{
        int to,next,dis,id;
    }edge[maxn * 2];
    int head[maxn],tot;
    void init(){
        for(int i = 0 ; i <= N + 1; i ++) head[i] = -1;
        tot = 0;
    }
    void add(int u,int v,int w,int id){
        edge[tot].to = v;
        edge[tot].id = id;
        edge[tot].next = head[u];
        edge[tot].dis = w;
        head[u] = tot++;
    }
    int nw[maxn];
    int Index[maxn];
    int dep[maxn],top[maxn],fa[maxn],val[maxn];
    int pos[maxn],size[maxn],son[maxn];
    const int SP = 20;
    int pa[maxn][SP];
    void dfs1(int t,int la){
        size[t] = 1; son[t] = t;
        pa[t][0] = la;
        for(int i = 1; i < SP; i ++) pa[t][i] = pa[pa[t][i - 1]][i - 1];
        int heavy = 0;
        for(int i = head[t]; ~i ; i = edge[i].next){
            int v = edge[i].to;
            if(v == la) continue;
            dep[v] = dep[t] + 1;
            fa[v] = t; val[v] = edge[i].dis;
            Index[edge[i].id] = v;
            dfs1(v,t);
            if(size[v] > heavy){
                heavy = size[v];
                son[t] = v;
            }
            size[t] += size[v];
        }
    }
    int lca(int u,int v){
        if(dep[u] < dep[v]) swap(u,v);
        int t = dep[u] - dep[v];
        for(int i = 0 ; i < SP; i ++){
            if(t & (1 << i)) u = pa[u][i];
        }
        for(int i = SP - 1; i >= 0 ; i --){
            int uu = pa[u][i],vv = pa[v][i];
            if(uu != vv){
                u = uu;
                v = vv;
            }
        }
        return u == v?u : pa[u][0];
    }
    int cnt;
    void dfs2(int t,int la){
        top[t] = la;
        pos[t] = ++cnt;
        nw[cnt] = val[t];
        if(son[t] == t) return;
        dfs2(son[t],la);
        for(int i = head[t]; ~i ; i = edge[i].next){
            int v = edge[i].to;
            if((fa[t] == v) || (v == son[t])) continue;
            dfs2(v,v);
        }
    }
    struct Tree{
        int l,r;
        int Min,Sum,Max;
        int lazy;
    }tree[maxn << 2];
    void Pushup(int t){
        tree[t].Min = min(tree[t << 1].Min,tree[t << 1 | 1].Min);
        tree[t].Max = max(tree[t << 1].Max,tree[t << 1 | 1].Max);
        tree[t].Sum = tree[t << 1].Sum + tree[t << 1 | 1].Sum;
    }
    void Build(int t,int l,int r){
        tree[t].l = l; tree[t].r = r;
        tree[t].lazy = 0;
        if(l == r){
            tree[t].Min = tree[t].Sum = tree[t].Max = nw[l];
            return;
        }
        int m = (l + r) >> 1;
        Build(t << 1,l,m); Build(t << 1 | 1,m + 1,r);
        Pushup(t);
    }
    void change(int t){
        tree[t].Sum = -tree[t].Sum;
        swap(tree[t].Max,tree[t].Min);
        tree[t].Max = -tree[t].Max;
        tree[t].Min = -tree[t].Min;
        tree[t].lazy ^= 1;
    }
    void Pushdown(int t){
        if(tree[t].lazy){
            change(t << 1);
            change(t << 1 | 1);
            tree[t].lazy = 0;
        }
    }
    void update1(int t,int p,int x){
        if(tree[t].l == tree[t].r){
            tree[t].Sum = tree[t].Max = tree[t].Min = x;
            return;
        }
        Pushdown(t);
        int m = (tree[t].l + tree[t].r) >> 1;
        if(p <= m) update1(t << 1,p,x);
        else update1(t << 1 | 1,p,x);
        Pushup(t);
    }
    void update2(int t,int l,int r){
        if(l <= tree[t].l && tree[t].r <= r){
            change(t);
            return;
        }
        Pushdown(t);
        int m = (tree[t].l + tree[t].r) >> 1;
        if(r <= m) update2(t << 1,l,r);
        else if(l > m) update2(t << 1 | 1,l,r);
        else{
            update2(t << 1,l,m);
            update2(t << 1 | 1,m + 1,r);
        }
        Pushup(t);
    }
    int query(int t,int l,int r,int p){
        if(l <= tree[t].l && tree[t].r <= r){
            if(p == 1) return tree[t].Sum;
            else if(p == 2) return tree[t].Max;
            return tree[t].Min;
        }
        Pushdown(t);
        int m = (tree[t].l + tree[t].r) >> 1;
        if(r <= m) return query(t << 1,l,r,p);
        else if(l > m) return query(t << 1 | 1,l,r,p);
        else{
            if(p == 1) return query(t << 1,l,m,p) + query(t << 1 | 1,m + 1,r,p);
            else if(p == 2) return max(query(t << 1,l,m,p),query(t << 1 | 1,m + 1,r,p));
            else return min(query(t << 1,l,m,p),query(t << 1 | 1,m + 1,r,p));
        }
    }
    void update(int u,int v){
        while(top[u] != top[v]){
            update2(1,pos[top[u]],pos[u]);
            u = fa[top[u]];
        }
        if(u != v) update2(1,pos[v] + 1,pos[u]);
    }
    int query(int u,int v,int p){
        int ans = 0;
        if(p == 2) ans = -INF;
        else if(p == 3) ans = INF;
        while(top[u] != top[v]){
            int t = query(1,pos[top[u]],pos[u],p);
            if(p == 1) ans += t;
            else if(p == 2) ans = max(ans,t);
            else ans = min(ans,t);
            u = fa[top[u]];
        }
        if(u != v){
            int t = query(1,pos[v] + 1,pos[u],p);
            if(p == 1) ans += t;
            else if(p == 2) ans = max(ans,t);
            else ans = min(ans,t);
        }
        return ans;
    }
    int main(){
        Sca(N); init();
        for(int i = 1; i <= N - 1; i ++){
            int u,v,w; Sca3(u,v,w);
            u++;v++;
            add(u,v,w,i); add(v,u,w,i);
        }
        int root = 1; dfs1(root,0);
        cnt = 0;
        dfs2(root,root);
        Build(1,1,N);
        Sca(M);
        while(M--){
            char op[4]; int u,v;
            scanf("%s%d%d",op,&u,&v);
            u++;v++; int l;
            if(op[0] == 'C') v--,u--;
            else l = lca(u,v);
            if(op[0] == 'C'){
                update1(1,pos[Index[u]],v);
            }else if(op[0] == 'N'){
                update(u,l); update(v,l);
            }else if(op[0] == 'S'){
                Pri(query(u,l,1) + query(v,l,1));
            }else if(op[1] == 'A'){
                Pri(max(query(u,l,2),query(v,l,2)));
            }else{
                Pri(min(query(u,l,3),query(v,l,3)));
            }
        }
        return 0;
    }

     

  • 相关阅读:
    Apache 2.4+php 5.4 安装
    Linux 进程状态
    解决Redhat Linux AS使用yum时出现This system is not registered with RHN的问题(改用CentOS的yum)
    nagios 事件处理
    awk调用shell命令的两种方法:system与print
    磁盘性能分析
    如何通过JQuery将DIV的滚动条滚动到指定的位置
    GCC Windows Linux 下编译学习1
    Linux命令
    GCC Windows Linux 下编译学习2
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/10357216.html
Copyright © 2011-2022 走看看