SPOJ375(树链剖分)

题目:Query on a tree

题意:给定一棵树,告诉了每条边的权值,然后给出两种操作:

(1)把第i条边的权值改为val

(2)询问a,b路径上权值最大的边

分析:本题与HDU3966差不多,区别就是:HDU3966是告诉树中点权的值,这里是边权。

所以我们可以转化,用边的孩子节点来表示该边。

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>

using namespace std;
const int N=50010;
const int INF=1<<30;

int n,tim;

int num[N],siz[N],top[N],son[N];
int dep[N],tid[N],rank[N],fa[N];
int head[N],to[2*N],next[2*N],w[2*N],edge;

struct Edge
{
    int u,v,c;
};
Edge tmp[2*N];

void Init()
{
    memset(head,-1,sizeof(head));
    memset(son,-1,sizeof(son));
    tim=0;
    edge=0;
}

void addedge(int u,int v,int c)
{
    to[edge]=v,w[edge]=c,next[edge]=head[u],head[u]=edge++;
    to[edge]=u,w[edge]=c,next[edge]=head[v],head[v]=edge++;
}

//树链剖分部分
void dfs1(int u,int father,int d)
{
    dep[u]=d;
    fa[u]=father;
    siz[u]=1;
    for(int i=head[u]; ~i; i=next[i])
    {
        int v=to[i];
        if(v!=father)
        {
            dfs1(v,u,d+1);
            siz[u]+=siz[v];
            if(son[u]==-1||siz[v]>siz[son[u]])
                son[u]=v;
        }
    }
}

void dfs2(int u,int tp)
{
    top[u]=tp;
    tid[u]=++tim;
    rank[tid[u]]=u;
    if(son[u]==-1) return;
    dfs2(son[u],tp);
    for(int i=head[u]; ~i; i=next[i])
    {
        int v=to[i];
        if(v!=son[u]&&v!=fa[u])
            dfs2(v,v);
    }
}

//线段树部分
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

int MAX[4*N];

void PushUP(int rt)
{
    MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);
}

void Build(int l,int r,int rt)
{
    if(l==r)
    {
        MAX[rt]=num[l];
        return;
    }
    int mid=(l+r)>>1;
    Build(lson);
    Build(rson);
    PushUP(rt);
}

void Update(int l,int r,int rt,int p,int val)
{
    if(l==r)
    {
        MAX[rt]=val;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)
        Update(lson,p,val);
    else
        Update(rson,p,val);
    PushUP(rt);
}

int Query(int l,int r,int rt,int L,int R)
{
    if(L<=l&&R>=r)
        return MAX[rt];
    int mid=(l+r)>>1;
    int ret=-INF;
    if(L<=mid) ret=max(ret,Query(lson,L,R));
    if(R>mid)  ret=max(ret,Query(rson,L,R));
    return ret;
}

void Change(int x,int val)
{
    if(dep[tmp[x].u]>dep[tmp[x].v])
        Update(2,n,1,tid[tmp[x].u],val);
    else
        Update(2,n,1,tid[tmp[x].v],val);
}

int query(int x,int y)
{
    int ans=-INF;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans=max(ans,Query(2,n,1,tid[top[x]],tid[x]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    if(x!=y) ans=max(ans,Query(2,n,1,tid[x]+1,tid[y]));
    return ans;
}

int main()
{
    char oper[15];
    int a,b,c,t;
    scanf("%d",&t);
    while(t--)
    {
        Init();
        scanf("%d",&n);
        for(int i=1; i<n; i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            tmp[i].u=a;tmp[i].v=b;tmp[i].c=c;
            addedge(a,b,c);
        }
        dfs1(1,1,1);
        dfs2(1,1);
        //用边的孩子节点来表示该边
        for(int i=1;i<n;i++)
        {
            if(dep[tmp[i].u]>dep[tmp[i].v])
                num[tid[tmp[i].u]]=tmp[i].c;
            else
                num[tid[tmp[i].v]]=tmp[i].c;
        }
        Build(2,n,1);
        while(1)
        {
            scanf("%s",oper);
            if(oper[0]=='D') break;
            scanf("%d%d",&a,&b);
            if(oper[0]=='Q')
                printf("%d
",query(a,b));
            else
                Change(a,b);
        }
    }
    return 0;
}


 

原文地址:https://www.cnblogs.com/pangblog/p/3294084.html