spoj 375 Query on a tree 树剖模板

#include <bits/stdc++.h>
using namespace std;

const int MAXN=10005;
struct Edge
{
    int to, next;
}edge[MAXN<<1];
int head[MAXN], tot;
int top[MAXN];	//子重链起点
int fa[MAXN];	//父节点
int deep[MAXN];	//深度
int num[MAXN];	//以节点x为根节点的子树包含的节点数量,包括x本身
int p[MAXN];	//重新建链之后节点的新的编号,也是加入到线段树中的位置
int fp[MAXN];	//根据编号得到实际的点编号
int son[MAXN];	//重链所在的节点
int pos;

void init()
{
    tot=0;
    memset(head, -1, sizeof(head));
    pos=0;
    memset(son, -1, sizeof(son));
}
void addedge(int u, int v)
{
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void dfs1(int u, int pre, int d)	//得到dep, fa, num, son数组,为建链预处理
{
    deep[u]=d;
    fa[u]=pre;
    num[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=pre)
        {
            dfs1(v, u, d+1);
            num[u]+=num[v];
            if(son[u]==-1 || num[v]>num[son[u]])
                son[u]=v;
        }
    }
}
void getpos(int u, int sp)	//sp->ancestor
{
    top[u]=sp;
    p[u]=pos++;
    fp[p[u]]=u;
    if(son[u]==-1)
        return ;
    getpos(son[u], sp);		//以根节点为起点,沿重边向下拓展,拉成重链。
    for(int i=head[u];i!=-1;i=edge[i].next)	//不在当前重链上的节点,都以该节点为起点向下重新拉一条重链。
    {
        int v=edge[i].to;
        if(v!=son[u] && v!=fa[u])
            getpos(v,  v);
    }
}

struct node
{
    int l, r;
    int Max;
}seg[MAXN*3];
void build(int i, int l, int r)
{
    seg[i].l=l;
    seg[i].r=r;
    seg[i].Max=0;
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    build(i<<1, l, mid);
    build((i<<1)|1, mid+1, r);
}
void pushup(int i)
{
    seg[i].Max=max(seg[i<<1].Max, seg[(i<<1)|1].Max);
}
void update(int i, int k, int val)
{
    if(seg[i].l==k && seg[i].r==k)
    {
        seg[i].Max=val;
        return ;
    }
    int mid=(seg[i].l+seg[i].r)>>1;
    if(k<=mid)
        update(i<<1, k, val);
    else
        update(i<<1|1, k, val);
    pushup(i);
}
int query(int i, int l, int r)
{
    if(seg[i].l==l && seg[i].r==r)
        return seg[i].Max;
    int mid=(seg[i].l+seg[i].r)>>1;
    if(r<=mid)
        return query(i<<1, l, r);
    else if(l>mid)
        return query((i<<1)|1, l, r);
    else
        return max(query(i<<1, l, mid), query((i<<1)|1, mid+1, r));
}
/*
记f1 = top[u],f2 = top[v]。
    当f1 <> f2时:不妨设dep[f1] >= dep[f2],那么就更新u到f1的父边的权值(logn),并使u = fa[f1]。
    当f1 = f2时:u与v在同一条重链上,若u与v不是同一点,就更新u到v路径上的边的权值(logn),否则修改完成;
    重复上述过程,直到修改完成。
*/
int find(int u, int v)
{
    int f1=top[u], f2=top[v];
    int tmp=0;
    while(f1!=f2)
    {
        if(deep[f1]<deep[f2])
        {
            swap(f1, f2);
            swap(u, v);
        }
        tmp=max(tmp, query(1, p[f1], p[u]));
        u=fa[f1];
        f1=top[u];
    }
    if(u==v)
        return tmp;
    if(deep[u]>deep[v])
        swap(u, v);
    return max(tmp, query(1, p[son[u]], p[v]));
}

int e[MAXN][3];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        init();
        int n;
        scanf("%d", &n);
        for(int i=0;i<n-1;i++)
        {
            scanf("%d%d%d", &e[i][0], &e[i][1], &e[i][2]);
            addedge(e[i][0], e[i][1]);
            addedge(e[i][1], e[i][0]);
        }
        dfs1(1, 0, 0);
        getpos(1,1);
        build(1, 0, pos-1);
        for(int i=0;i<n-1;i++)
        {
            if(deep[e[i][0]]>deep[e[i][1]])
                swap(e[i][0], e[i][1]);
            update(1, p[e[i][1]], e[i][2]);
        }
        char op[10];
        while(~scanf("%s", op))
        {
            if(op[0]=='D')
                break;
            int u, v;
            scanf("%d%d", &u, &v);
            if(op[0]=='Q')
                printf("%d\n", find(u, v));
            else
                update(1, p[e[u-1][1]], v);
        }
    }
    return 0;
}

//SPOJ 375

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值