SPOJ 375. Query on a tree【树链剖分】

http://www.spoj.pl/problems/QTREE/

给一颗树,每条边有一个权值。有两种操作:1、修改某条边的值;2、询问a、b两点路径上边权的最大值。

树链剖分。


#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string.h>
using namespace std;
#define maxn 100100
#define lson (pos<<1)
#define rson (pos<<1|1)
//-----------------------------------建边部分-------------------------
int cnt, head[maxn];
struct Edge
{
    int to,next;
}e[maxn*3];
void Add_edge(int a, int b)
{
    e[cnt].to=b;
    e[cnt].next=head[a];
    head[a]=cnt++;
}
//-----------------------------------树链部分-------------------------
//记siz[v]表示以v为根的子树的节点数,dep[v]表示v的深度(根深度为1)
//top[v]表示v所在的链的顶端节点,fa[v]表示v的父亲
//son[v]表示与v在同一重链上的v的儿子节点(姑且称为重儿子)
//ti[v]表示v与其父亲节点的连边(姑且称为v的父边)在线段树中的位置
int son[maxn], top[maxn], sz[maxn], dep[maxn], fa[maxn], ti[maxn], dfs_clock;
int n,m;
void dfs_find(int u, int pa, int depth)
{
    son[u]=0;sz[u]=1;dep[u]=depth;fa[u]=pa;
    for(int i = head[u]; i != -1; i = e[i].next)
    {
        int v=e[i].to;
        if(v==pa)continue;
        dfs_find(v,u,depth+1);
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]])son[u]=v;
    }
}
void dfs_time(int u, int pa)
{
    ti[u]=++dfs_clock; top[u]=pa;
    if(son[u]!=0)dfs_time(son[u],top[u]);
    for(int i = head[u]; i != -1; i = e[i].next)
        if(e[i].to!=son[u]&&e[i].to!=fa[u])
            dfs_time(e[i].to, e[i].to);
}
//-----------------------------------线段树部分-------------------------
struct node
{
   int l,r,val,mx;
   int mid(){return (l+r)>>1;}
}tree[maxn<<2];
void build(int pos, int l, int r)
{
    tree[pos].l=l;tree[pos].r=r;tree[pos].mx=tree[pos].val=-0x7ffffff;
    if(l==r)return ;
    int mid=tree[pos].mid();
    build(lson,l,mid);
    build(rson,mid+1,r);
}
void update(int pos, int id, int w)
{
    if(tree[pos].l==tree[pos].r)
    {
        tree[pos].mx=tree[pos].val=w;
        return ;
    }
    int mid=tree[pos].mid();
    if(mid>=id)update(lson,id,w);
    else update(rson,id,w);
    tree[pos].mx=max(tree[lson].mx,tree[rson].mx);
}
int query(int pos, int L, int R)
{
    if(L<=tree[pos].l&&tree[pos].r<=R)
        return tree[pos].mx;
    int mid=tree[pos].mid();
    int ans=-0x7ffffff;
    if(mid>=L)ans=max(ans, query(lson,L,R));
    if(mid<R)ans=max(ans, query(rson,L,R));
    return ans;
}
int lca(int x, int y)      //这里传的参数是实际点x和y,不是映射后的点
{
    int ans=-0x7ffffff;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=max(ans,query(1,ti[top[x]],ti[x]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)
        ans=max(ans,query(1,ti[x]+1,ti[y])); //这里的ti[x]指的是x与其父亲的边,所以一定注意+1
    return ans;
}
void ini()
{
    cnt=dfs_clock=0;
    memset(head,-1,sizeof(head));
}
int da[maxn][3];
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        ini();
        for(int i = 1; i < n; i++)
        {
            scanf("%d%d%d",&da[i][0],&da[i][1],&da[i][2]);
            Add_edge(da[i][0],da[i][1]);
            Add_edge(da[i][1],da[i][0]);
        }
        dfs_find(1,1,1);
        dfs_time(1,1);
        build(1,2,n);
        for(int i = 1; i < n; i++)
        {
            if(dep[da[i][0]]>dep[da[i][1]])swap(da[i][0],da[i][1]);
            update(1,ti[da[i][1]],da[i][2]);
        }
        char he[100];
        while(1)
        {
            scanf("%s",he);
            if(he[0]=='D')break;
            if(he[0]=='Q')
            {
                int a,b;scanf("%d%d",&a,&b);
                printf("%d\n",lca(a,b));
            }
            else
            {
                int a,b;scanf("%d%d",&a,&b);
                update(1,ti[da[a][1]],b);
            }
        }
        printf("\n");
    }
    return 0;
}


你可能感兴趣的:(SPOJ 375. Query on a tree【树链剖分】)