SPOJ375 Query on a tree

题目链接:点击打开链接

题意:有一棵n(n<=10000)个节点的树,每条边有一个权值wi.现有两种操作:1.改变第i条边的权值,2.询问a到b路径上最大的边权

题解:树链剖分入门题。学习树链剖分请点这里

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long LL;

const int N=10000+10;
const int E=20000+10;

int n;
int d[N],Fa[N],Size[N],Top[N],p[N],Son[N];
int T[N<<2];
int pos;
int Edge[N][3];
vector<int>V[N];

void dfs1(int u,int Pre,int Dep)//第一遍dfs求Fa,d,Size,Son
{
    d[u]=Dep;
    Fa[u]=Pre;
    Size[u]=1;
    for (int i=0;i<int(V[u].size());i++){
        int v=V[u][i];
        if (v!=Pre){
            dfs1(v,u,Dep+1);
            Size[u]+=Size[v];
            if (Son[u]==-1 || Size[v]>Size[Son[u]]) Son[u]=v;
        }
    }
}
void dfs2(int u,int sp)//top和p
{
    Top[u]=sp;
    p[u]=pos++;
    if (Son[u]==-1) return ;
    dfs2(Son[u],sp);
    for (int i=0;i<int(V[u].size());i++){
        int v=V[u][i];
        if (Fa[u]!=v && Son[u]!=v) dfs2(v,v);
    }
}
void Build(int p,int L,int R)
{
    T[p]=0;
    if (L==R)return ;
    int mid=(L+R)>>1;
    Build(p<<1,L,mid);
    Build((p<<1)^1,mid+1,R);
}
void Insert(int p,int L,int R,int pos,int v)
{
    if (L==R){
        T[p]=v;return ;
    }
    int mid=(L+R)>>1;
    if (pos<=mid) Insert(p+p,L,mid,pos,v);
    else Insert(p+p+1,mid+1,R,pos,v);
    T[p]=max(T[p+p],T[p+p+1]);
}
int Find(int p,int L,int R,int l,int r)
{
    if (L==l && R==r)return T[p];
    int mid=(L+R)>>1;
    if (r<=mid)return Find(p+p,L,mid,l,r);
    else if (mid<l)return Find(p+p+1,mid+1,R,l,r);
    else return max(Find(p+p,L,mid,l,mid),Find(p+p+1,mid+1,R,mid+1,r));
}
int Query(int u,int v)
{
    int f1=Top[u],f2=Top[v];
    int tmp=0;
    while (f1!=f2){
        if (d[f1]<d[f2]){
            swap(f1,f2);swap(u,v);
        }
        tmp=max(tmp,Find(1,1,pos,p[Top[u]],p[u]));
        u=Fa[f1];f1=Top[u];
    }
    if (u==v)return tmp;
    if (d[u]<d[v])swap(u,v);
    return max(tmp,Find(1,1,pos,p[Son[v]],p[u]));
}
void work()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)V[i].clear();
    for (int i=1;i<n;i++){
        scanf("%d%d%d",&Edge[i][0],&Edge[i][1],&Edge[i][2]);
        V[Edge[i][0]].push_back(Edge[i][1]);
        V[Edge[i][1]].push_back(Edge[i][0]);
    }
    pos=1;
    for (int i=1;i<=n;i++)Son[i]=-1;
    dfs1(1,0,0);
    dfs2(1,1);
    Build(1,1,pos);
    for (int i=1;i<n;i++){
        if (d[Edge[i][0]]<d[Edge[i][1]])
            swap(Edge[i][0],Edge[i][1]);
        Insert(1,1,pos,p[Edge[i][0]],Edge[i][2]);
    }
    char str[100];
    while (scanf("%s",str)!=EOF && str[0]!='D'){
        int x,y;scanf("%d%d",&x,&y);
        if (str[0]=='Q'){
            printf("%d\n",Query(x,y));
        }else Insert(1,1,pos,p[Edge[x][0]],y);
    }
}
int main()
{
    //freopen("1.txt","r",stdin);
    int Case;scanf("%d",&Case);
    while (Case--)work();
    return 0;
}


发布了74 篇原创文章 · 获赞 30 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/MustImproved/article/details/52605777
今日推荐