zoukankan      html  css  js  c++  java
  • 洛谷 P4114 Qtree1

    Qtree系列都跟树有着莫大的联系,这道题当然也不例外

    我是题面

    读完题,我们大概就知道了,这道题非常简单,可以说是模板题。树剖+线段树轻松解决

    直接看代码吧

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cctype>
    #define ll long long
    #define gc() getchar()
    #define maxn 100010
    using namespace std;
    
    inline ll read(){     //很朴素的快读,不多解释
        ll a=0;int f=0;char p=gc();
        while(!isdigit(p)){f|=p=='-';p=gc();}
        while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
        return f?-a:a;
    }
    void write(ll a){     //很朴素的快写,也不多解释
        if(a>9)write(a/10);
        putchar(a%10+'0');
    }
    int n,a[maxn];    //a数组表示点与父亲连边的长度
    
    int tot,head[maxn];
    struct ahaha1{     //前向星存边
        int w,to,next;
    }e[maxn<<1];
    inline void add(int u,int v,int w){
        e[tot].w=w;e[tot].to=v;e[tot].next=head[u];head[u]=tot++;
    }
    
    int f[maxn],sz[maxn],dep[maxn],son[maxn];     //f表示点的父亲,sz表示点的子树上节点个数,dep表示节点的深度,son表示子树最大的子节点
    void dfs(int u,int fa){
        int maxa=0;sz[u]=1;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;if(v==fa)continue;
            f[v]=u;dep[v]=dep[u]+1;a[v]=e[i].w;
            dfs(v,u);sz[u]+=sz[v];
            if(sz[v]>maxa)maxa=sz[v],son[u]=v;
        }
    }
    int b[maxn],in[maxn],top[maxn];    //b表示当前编号所指向的点,in表示点的编号,top表示点所在链的顶端
    void dfs(int u,int fa,int topf){
        in[u]=++tot;b[tot]=u;top[u]=topf;
        if(!son[u])return;
        dfs(son[u],u,topf);
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;if(v==fa||v==son[u])continue;
            dfs(v,u,v);
        }
    }
    
    #define lc p<<1
    #define rc p<<1|1
    struct ahaha2{     //线段树太简单不解释
        int v;
    }t[maxn<<2];
    inline void pushup(int p){
        t[p].v=max(t[lc].v,t[rc].v);
    }
    void build(int p,int l,int r){
        if(l==r){t[p].v=a[b[l]];return;}
        int m=l+r>>1;
        build(lc,l,m);build(rc,m+1,r);
        pushup(p);
    }
    void update(int p,int l,int r,int L,int z){
        if(l==r){t[p].v=z;return;}
        int m=l+r>>1;
        if(m>=L)update(lc,l,m,L,z);
        else update(rc,m+1,r,L,z);
        pushup(p);
    }
    int query(int p,int l,int r,int L,int R){
        if(l>R||r<L)return 0;
        if(L<=l&&r<=R)return t[p].v;
        int m=l+r>>1;
        return max(query(lc,l,m,L,R),query(rc,m+1,r,L,R));
    }
    
    inline void solve_1(){    //从第0条边开始存,每条边存两次,所以输入的第i条边对应的是第2*i-2和第2*i-1条边,谁是儿子改谁
        int x=read()*2-2,w=read(),u=e[x].to,v=e[x+1].to;
        if(f[v]==u)update(1,1,n,in[v],w);
        else update(1,1,n,in[u],w);
    }
    inline void solve_2(){      //链上查询
        int x=read(),y=read(),ans=0;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            ans=max(ans,query(1,1,n,in[top[x]],in[x]));    //由于存的是与父亲的距离,而top的父亲直接取所以此处无需加1
            x=f[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        ans=max(ans,query(1,1,n,in[x]+1,in[y]));     //但是最后一次存储必须加1否则会多询问一条边
        write(ans);putchar('
    ');
    }
    
    int main(){memset(head,-1,sizeof head);
        n=read();
        for(int i=1;i<n;++i){
            int x=read(),y=read(),w=read();
            add(x,y,w);add(y,x,w);
        }
        tot=0;dfs(1,-1);dfs(1,-1,1);
        build(1,1,n);
        char z[10];
        while(1){
            scanf("%s",z);
            if(z[0]=='D')break;
            switch(z[0]){
                case 'C':solve_1();break;
                case 'Q':solve_2();break;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    学习的原动力
    “六顶思考帽”给我的启示
    关于DataSet与Strongly typed DataSet几点思考(原创)
    设计模式之Singleton和Factory
    CentOS修改网络配置
    Proxmox VE(PVE)安装教程
    CentOS开启SELinux导致samba无法访问的解决办法
    nano编辑器使用教程
    CentOS 如何挂载硬盘
    PVE硬盘直通
  • 原文地址:https://www.cnblogs.com/hanruyun/p/9373059.html
Copyright © 2011-2022 走看看