spoj 375 Query on a tree 樹鏈剖分

題目連接:http://www.spoj.com/problems/QTREE/

題目大意:給你一棵帶邊權的樹,有兩個操作,1,改變某條邊的邊權;2,查詢兩個點之間的最大邊權

解題思路:解題思路是樹鏈剖分。其實就是沒有辦法直接暴力了,然後找一個方法,將邊分分類,最好能降到一維,然後再維護一下,搞一搞,就行了

這個題的特點是樹的結構不會變!!!而且有一個神結論(我比較弱,就當做是神結論吧),將一棵樹分完輕重邊之後,任意一個點到根節點的輕邊和重鏈的個數都不會超過logn。這是有個非常優美的性質,也就是說現在,對於詢問,只要分別處理兩個節點到最近公共祖先路徑上的最大值,就得到最終的結果了

//#pragma comment(linker,"/STACK:102400000,102400000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define ll long long
#define db double
#define PB push_back
using namespace std;

const int N = 10005;
const int M = 2*N;
int d[N][3],num;
int head[N],cost[M],to[M],next[M],nedge;

void init()
{
    memset(head,-1,sizeof(head));
    nedge=0;
    num=0;
}

void add(int a,int b,int c)
{
    cost[nedge]=c,to[nedge]=b,next[nedge]=head[a],head[a]=nedge++;
}

int son[N],tol[N],dep[N],fa[N];
void get_son_dep(int k,int dp)
{
    tol[k]=1,son[k]=0,dep[k]=dp;
    for(int i=head[k];i>=0;i=next[i])
    {
        if(to[i]!=fa[k])
        {
            fa[to[i]]=k;
            get_son_dep(to[i],dp+1);
            tol[k]+=tol[to[i]];
            if(tol[to[i]]>tol[son[k]]) son[k]=to[i];
        }
    }
}

int w[N],top[N];
void build(int k,int rt)
{
    w[k]=++num,top[k]=rt;
    if(son[k]!=0) build(son[k],rt);
    for(int i=head[k];i>=0;i=next[i])
    {
        if(to[i]!=fa[k]&&to[i]!=son[k])
        {
            build(to[i],to[i]);
        }
    }
}

struct node
{
    int l,r;
    int max_val;
} tr[4*N];

void build_tr(int k,int l,int r)
{
    tr[k].l=l,tr[k].r=r;
    tr[k].max_val=0;
    if(l<r)
    {
        int mid=(l+r)>>1;
        build_tr(k<<1,l,mid);
        build_tr((k<<1)|1,mid+1,r);
    }
}

void update(int k,int lr,int val)
{
    if(tr[k].l==tr[k].r)
    {
        tr[k].max_val=val;
        return;
    }
    int mid=(tr[k].l+tr[k].r)>>1;
    if(lr<=mid) update(k<<1,lr,val);
    else update((k<<1)|1,lr,val);
    tr[k].max_val=max(tr[k<<1].max_val,tr[(k<<1)|1].max_val);
}

int query(int k,int l,int r)
{
    if(tr[k].l==l&&tr[k].r==r)
    {
        return tr[k].max_val;
    }
    int mid=(tr[k].l+tr[k].r)>>1;
    if(r<=mid) return query(k<<1,l,r);
    else if(l>=mid+1) return query((k<<1)|1,l,r);
    else return max(query(k<<1,l,mid),query((k<<1)|1,mid+1,r));
}

int find_ans(int a,int b)
{
    int res=0;
    int tpa=top[a],tpb=top[b];
    while(tpa!=tpb)
    {
        if(dep[tpa]<dep[tpb]) {swap(tpa,tpb),swap(a,b);}
        res=max(res,query(1,w[tpa],w[a]));
        a=fa[tpa],tpa=top[a];
    }
    if(dep[a]<dep[b]) swap(a,b);
    if(a!=b) res=max(res,query(1,w[son[b]],w[a]));
    return res;
}

int get_int()
{
    char c;
    while((c=getchar())<'0'||c>'9');
    int res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    return res;
}

char str[50];
int main()
{
#ifdef PKWV
    freopen("in.in","r",stdin);
#endif // PKWV
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        n=get_int();
//        scanf("%d",&n);
        int rt=n/2+1;
        init();
        for(int i=1;i<n;i++)
        {
            int a,b,c;
            a=get_int();b=get_int(),c=get_int();
//            scanf("%d%d%d",&a,&b,&c);
            d[i][0]=a,d[i][1]=b,d[i][2]=c;
            add(a,b,c),add(b,a,c);
        }
        fa[rt]=0;
        get_son_dep(rt,0);
        build(rt,rt);
        build_tr(1,1,num);
        for(int i=1;i<n;i++)
        {
            if(dep[d[i][0]]>dep[d[i][1]]) swap(d[i][0],d[i][1]);
            update(1,w[d[i][1]],d[i][2]);
        }
        while(scanf("%s",str)&&str[0]!='D')
        {
            int a,b;
            a=get_int();b=get_int();
//            scanf("%d%d",&a,&b);
            if(str[0]=='C') update(1,w[d[a][1]],b);
            else printf("%d\n",find_ans(a,b));
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章