• SPOJ QTREE


    • 题意: 一个有边权树,操作是询问节点(a到b)所经过边的最大权和修改某边的边权
    • 思路: 树链剖分,将边权下放到儿子的点权即可
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    
    #define ll long long 
    #define FOR(i,l,r) for(int i = l ; i <= r ;++i ) 
    #define inf 0x3f3f3f3f
    #define EPS (1e-9)
    #define ALL(T)  T.begin(),T.end()
    #define lson(i)		i<<1
    #define rson(i)		(i<<1|1)
    using namespace std; 
    
    const int maxn =30010;
    struct Edge{
        int to,next,w;
    }edge[maxn*2];
    
    int head[maxn],tot;
    int top[maxn];  // 所在重链的顶端节点
    int fa[maxn];   // 父亲
    int deep[maxn]; // 深度
    int num[maxn];  // 儿子个数
    int p[maxn];    // 在dfs序的位置  
    int fp[maxn];   // 位置节点号的反向映射
    int son[maxn]; // 重儿子
    int pos;
    
    void addedge(int u,int v,int w){
        edge[tot].to = v;
        edge[tot].next = head[u];
        edge[tot].w = w;
        head[u] = tot++;
    }
    
    void init(){
        memset(head,-1,sizeof(head));
        memset(son,-1,sizeof(son));
        tot = 0;
        pos = 1;
    }
    
     //第一遍dfs   处理fa,num,deep,son
    void dfs1(int u,int pre,int d){
        deep[u] = d;
        fa[u] = pre;
        num[u] = 1;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v = edge[i].to;
            if(v!=pre){
                dfs1(v,u,d+1);
                num[u] += num[v];
                if(son[u] == -1 || num[v] > num[son[u]])
                    son[u] = v;
            }
        }
    }
    // 第二遍dfs  处理 top,p,fp
    void dfs2(int u,int sp){
        top[u] = sp;        
        p[u] = pos++;
        fp[p[u]] = u;
        if(son[u]== -1)    return ;
        dfs2(son[u],sp);    // 当前链继续走重儿子
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v = edge[i].to;
            if( v!= son[u] && v!=fa[u])
                dfs2(v,v);  // 以自己为链首的新链
        }
    }
    
    int a[maxn];
    struct node{
        int l,r;
        int sum,ma;
    }seg[maxn*4];
    
    void push_up(int p){
        seg[p].ma = max(seg[lson(p)].ma,seg[rson(p)].ma);
    }
    
    void build(int pp,int l,int r){
        seg[pp].l = l;
        seg[pp].r = r;
        if(l==r){
            // 反向映射到原来的节点
            // seg[pp].ma = seg[pp].sum = a[fp[l]];
            return;
        }
        int mid = (l+r)>>1;
        build(lson(pp),l,mid);
        build(rson(pp),mid+1,r);
        // push_up(pp);
    }
    
    void update(int p,int l,int r,int val){
        if(seg[p].l >= l && seg[p].r <= r){
            // seg[p].sum = val;
            seg[p].ma = val;
            return;
        }
        int mid = (seg[p].r+seg[p].l)>>1;
        if(l<=mid)  update(lson(p),l,r,val);
        if(r>mid)   update(rson(p),l,r,val);
        push_up(p);
    }
    
    int qmax(int p,int l,int r){
        if(seg[p].l >= l && seg[p].r <= r){
            return seg[p].ma;
        }
        int res = -inf;
        int mid = (seg[p].r+seg[p].l)>>1;
        if(l<=mid)  res = max(res,qmax(lson(p),l,r));
        if(r>mid)   res = max(res,qmax(rson(p),l,r));
        return res;
    }
    
    int fmax(int u,int v){
        int res = -1e9;
        int tu = top[u], tv = top[v];
        while(tu != tv){
            if(deep[tu]< deep[tv]){
                swap(tu,tv);
                swap(u,v);
            }
            res=max(res,qmax(1,p[tu],p[u]));
            u = fa[tu];
            tu = top[u];
        }
        if(deep[u] > deep[v])   swap(u,v);
        res = max(res,qmax(1,p[son[u]],p[v]));
        return res;
    }
    
    
    int n;
    int main(){
    int t;
    cin >> t;
    while(t--){
        scanf("%d",&n);
        int fr,to,w;
        init();
        FOR(i,1,n-1){
            scanf("%d%d%d",&fr,&to,&w);
            addedge(fr,to,w);
            addedge(to,fr,w);
        }
        dfs1(1,0,0);
        dfs2(1,1);
        // FOR(i,1,n) {
        //     scanf("%d",&a[i]);
        // }
        build(1,1,n);
        for(int i=0;i< tot;i+=2){
            if(fa[edge[i].to]==edge[i+1].to){
                update(1,p[edge[i].to],p[edge[i].to],edge[i].w);
                // a[edge[i].to] = edge[i].w;
            }else{
                update(1,p[edge[i+1].to],p[edge[i+1].to],edge[i+1].w);
                // a[edge[i+1].to] = edge[i].w;
            }
        }
        // FOR(i,1,n){
        //     printf("%d %d %d %d %d %d
    ",top[i],fa[i],deep[i],num[i],p[i],son[i]);
        // }cout << endl;
        char op[10];
        while(scanf("%s",op) && op[0]!='D'){
            scanf("%d%d",&fr,&to);
            if(op[0]=='Q')
                if(fr==to) printf("0
    ");
                else printf("%d
    ",fmax(fr,to));
            else{
                Edge e = edge[fr*2-1];
                Edge e2 = edge[fr*2-2];
                w = fa[e.to]==e2.to ? e.to : e2.to;
                update(1,p[w],p[w],to);
            }
        }
    }
       
        return 0;
    }
    
    

    注意: 当跳到两个节点在一条链时,询问的不是 p[u] 到 p[v], 而是p[son[u]] 到 p[v] 因为u节点存的是u到其父亲的边,u到v是不会经过的

    博客连接

  • 相关阅读:
    【洛谷】NOIP提高组模拟赛Day2【动态开节点/树状数组】【双头链表模拟】
    【10.7校内测试】【队列滑窗】【2-sat】【贪心+栈二分+线段树(noip模拟好题)】【生日祭!】
    【10.6校内测试】【小模拟】【hash+线段树维护覆盖序列】
    【洛谷】NOIP提高组模拟赛Day1【组合数学】【贪心+背包】【网络流判断是否满流以及流量方案】
    【10.5校内测试】【DP】【概率】
    【洛谷】1174:打砖块
    【10.4校内测试】【轮廓线DP】【中国剩余定理】【Trie树+博弈】
    【10.3校内测试【国庆七天乐!】】【DP+组合数学/容斥】【spfa多起点多终点+二进制分类】
    【二分图】性质
    【9.23校内测试】【抽屉原理】【乱搞??(找众数】【Trie】
  • 原文地址:https://www.cnblogs.com/xxrlz/p/11262268.html
Copyright © 2020-2023  润新知