首页 > 其他 > 详细

树链剖分-P4114 Qtree1

时间:2021-05-15 12:13:58      阅读:27      评论:0      收藏:0      [点我收藏+]

题意

  • 给定一棵 n 个节点的树,有两种操作:
  • CHANGE i t 把第 i 条边的边权变成 t
  • QUERY a b 输出从 a 到 b 的路径上最大的边权。当 a=b 时,输出 0
  • DONE 表示输入结束。

分析

树链剖分板子题。

将点权转换为边权:边上信息转移到深度较大的点上。

但是这样做需要注意一个问题:每次查询时,LCA 的节点维护的信息是它上方的边,因此这个点不能被查询到。

 

CODE:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson rt<<1
#define rson rt<<1|1
inline char nc() {
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
template <class Tp> inline void read(register Tp &s) {
    s=0;
    register bool neg=0;
    register char c=nc();
    for(;c<0||c>9;c=nc()) neg|=(c==-);
    for(;c>=0&&c<=9;s=s*10+(c^48),c=nc());
    s=(neg?-s:s);
}

const int N=1e5+5,M=2e5+5;
int n,idx,dfn[N],seq[N],U[N],V[N],W[N],val[N],fa[N],dep[N],top[N],sz[N],hvy[N];
int tot,lnk[N],ter[M],nxt[M],wei[M],seg[N<<2];

void add(int u,int v,int w) {
    ter[++tot]=v,wei[tot]=w,nxt[tot]=lnk[u],lnk[u]=tot;
}
void dfs1(int u,int f) {
    fa[u]=f,dep[u]=dep[f]+1,sz[u]=1,hvy[u]=top[u]=0;
    for(int i=lnk[u];i;i=nxt[i]) {
        int v=ter[i];
        if(v==f) continue;
        val[v]=wei[i];
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[hvy[u]]<sz[v]) hvy[u]=v;
    }
}
void dfs2(int u,int tp) {
    dfn[u]=++idx,seq[idx]=u,top[u]=tp;
    if(!hvy[u]) return;
    dfs2(hvy[u],tp);
    for(int i=lnk[u];i;i=nxt[i]) {
        int v=ter[i];
        if(v==fa[u]||v==hvy[u]) continue;
        dfs2(v,v);
    }
}
void pushup(int rt) {
    seg[rt]=std::max(seg[lson],seg[rson]);
}
void build(int rt,int l,int r) {
    if(l==r) {
        seg[rt]=val[seq[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    pushup(rt);
}
void modify(int x,int rt,int l,int r,int val) {
    if(l==r) {
        seg[rt]=val;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) modify(x,lson,l,mid,val);
    else modify(x,rson,mid+1,r,val);
    pushup(rt);
}
int query(int x,int y,int rt,int l,int r) {
    if(x>y) return 0;
    if(x<=l&&r<=y) return seg[rt];
    int mid=(l+r)>>1,res=0;
    if(x<=mid) res=std::max(res,query(x,y,lson,l,mid));
    if(mid<y) res=std::max(res,query(x,y,rson,mid+1,r));
    return res;
}
int chainQuery(int u,int v) {
    if(u==v) return 0;
    int res=0;
    for(int fu=top[u],fv=top[v];fu^fv;u=fa[fu],fu=top[u]) {
        if(dep[fu]<dep[fv]) std::swap(u,v),std::swap(fu,fv);
        res=std::max(res,query(dfn[fu],dfn[u],1,1,n));
    }
    if(dep[u]>dep[v]) std::swap(u,v);
    res=std::max(res,query(dfn[u]+1,dfn[v],1,1,n));
    return res;
}
int main() {
    read(n);
    for(int i=1;i<n;++i) {
        int u,v,w;
        read(u),read(v),read(w);
        add(u,v,w),add(v,u,w);
        U[i]=u,V[i]=v,W[i]=w;
    }
    dfs1(1,0),dfs2(1,1),build(1,1,n);
    while(1) {
        char c=nc();
        while(c<A||c>Z) c=nc();
        if(c==D) break;
        int x,y;
        read(x),read(y);
        if(c==C) {
            int u=U[x],v=V[x];
            if(fa[v]==u) std::swap(u,v);
            modify(dfn[u],1,1,n,y);
        } else {
            printf("%d\n",chainQuery(x,y));
        }
    }
    return 0;
}

 

树链剖分-P4114 Qtree1

原文:https://www.cnblogs.com/zzWutianyu/p/14770585.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!