P4114 Qtree1

边权转化为点权的操作

把边权放在深度更大的点上

查询时候不查询公共祖先

接下来就是线段树单点,区间max

// Problem: P4114 Qtree1
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4114
// Memory Limit: 500 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<vector>
using namespace std;
const int N=1e5+9;
int n;
int a[N];
//树剖
//1.转成线性部分
struct edge{
	int u,v,w;
}ee[N];
vector<edge> e[N];
void add(int u,int v,int w){//记录边
    e[u].push_back({v,u,w});
    e[v].push_back({u,v,w});
}
int fa[N],dep[N],sz[N],wc[N],dis[N];
void dfs1(int u,int f){//fa dep sz wc
    fa[u]=f;
    sz[u]=1;
    dep[u]=dep[f]+1;
    for(auto & [x,y,z] : e[u]){
    	if(x==f){
    		dis[u]=z;//边权给儿子
    		continue;
    	}
        if(x!=f){
            dfs1(x,u);
            sz[u]+=sz[x];
            if(sz[x]>sz[wc[u]]){
                wc[u]=x;
            }
        }
    }
}
int dfn[N],rdfn[N],top[N],vistime;
void dfs2(int u,int Top){//dfn rdfn top
    dfn[u]=++vistime;
   	a[vistime]=dis[u];
    top[u]=Top;
    if(wc[u]){
        dfs2(wc[u],Top);
        for(auto & [x,y,z] : e[u]){
            if(x!=wc[u] && x!=fa[u]){
                dfs2(x,x);
            }
        }
    }
}
//2.线段树维护
struct SEG{
    #define INF (1<<31)
    #define ll long long
    #define tl(id) (id<<1)
    #define tr(id) (id<<1|1)
    #define li inline
    struct node{
       int mx;
    }seg[N<<2];
    #define pushup(id) seg[id].mx=max(seg[tl(id)].mx,seg[tr(id)].mx)
    li int inrange(int L,int R,int l,int r){return l<=L && R<=r;}
    li int outofrange(int L,int R,int l,int r){return L>r || R<l;}
    li void build(const int id,int l,int r){
        if(l==r){
            seg[id].mx=a[l];
            return;
        }
        int mid=(l+r)>>1;
        build(tl(id),l,mid);
        build(tr(id),mid+1,r);
        pushup(id);
    }
    li ll query(int id,int L,int R,int l,int r){
        if(inrange(L,R,l,r)){
            return seg[id].mx;
        }else if(!outofrange(L,R,l,r)){
            int mid=(L+R)>>1;
            return max(query(tl(id),L,mid,l,r),query(tr(id),mid+1,R,l,r));
        }else{
            return 0;
        }
    }
    li void update(int id,int l,int r,int pos,int v){
    	if(l==r){
    		seg[id].mx=v;
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(mid>=pos){
			update(tl(id),l,mid,pos,v);    		
    	}else{
    		update(tr(id),mid+1,r,pos,v);
    	}
    	pushup(id);
    }
}tr;
//3.找LCA,同时完成操作
ll ask(int u,int v){
	if(u==v){
		return 0;
	}
    ll res=0;
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]){
            swap(u,v);
        }
        res=max(res,tr.query(1,1,n,dfn[top[u]],dfn[u]));
        u=fa[top[u]];
    }
    if(dfn[u]>dfn[v]){
    	swap(u,v);
    }
    res=max(res,tr.query(1,1,n,dfn[u]+1,dfn[v]));//去掉公共祖先
    return res;
}
int main(){
	cin>>n;
	for(int i=1;i<=n-1;i++){
		int u,v,w;
		cin>>u>>v>>w;
		ee[i]={u,v,w};
		add(u,v,w);
	}
	dfs1(1,0);
	dfs2(1,1);
	tr.build(1,1,n);
	string op;
	while(cin>>op){
		if(op=="CHANGE"){
			int i,t;
			cin>>i>>t;
			if(dep[ee[i].u]>dep[ee[i].v]){//放在深度更大的点
				i=ee[i].u;
			}else{
				i=ee[i].v;
			}
			tr.update(1,1,n,dfn[i],t);
		}else if(op=="QUERY"){
			int a,b;
			cin>>a>>b;
			cout<<ask(a,b)<<'\n';
		}else{
			break;
		}
	}
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值