Spoj375 Qtree

Description
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3…N1.
We will ask you to perfrom some instructions of the following form:
CHANGE i ti : change the cost of the i -th edge to ti
or
QUERY a b : ask for the maximum edge cost on the path from node a to node b .

Input
The first line of input contains an integer t , the number of test cases (t<=20). t test cases follow.
For each test case:
In the first line there is an integer N(N<=10000),
In the next N1 lines, the i -th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of cost c(c<=1000000),
The next lines contain instructions “CHANGE i ti” or “QUERY a b”,
The end of each test case is signified by the string “DONE”.
There is one blank line between successive tests.

Output
For each “QUERY” operation, write one integer representing its result.

Sample Input
1
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Sample Output
1
3

题目解释
给一棵共有 n(n<=10000) 个结点的树,每条边都有一个权值,要求维护一个数据结构,支持如下操作:
1. 修改某条边的权值;
2. 询问某两个结点之间的唯一通路上的最大边权。
其中操作的总次数为 q。

思路
树链剖分水题(其实也不是很水),把边权放到每个点就可以了。

代码

#include <cstdio>
#include <algorithm>
#include <cstring>

const int maxn=10000;
const int inf=1000000000;

struct sigment_tree
{
    int val[(maxn<<2)+10];

    int updata(int now)
    {
        val[now]=std::max(val[now<<1],val[now<<1|1]);
        return 0;
    }

    int build(int now,int left,int right)
    {
        if(left==right)
        {
            val[now]=0;
            return 0;
        }
        int mid=(left+right)>>1;
        build(now<<1,left,mid);
        build(now<<1|1,mid+1,right);
        updata(now);
        return 0;
    }

    int modify(int now,int left,int right,int findnum,int changeval)
    {
        if((findnum<left)||(findnum>right))
        {
            return 0;
        }
        if(left==right)
        {
            val[now]=changeval;
            return 0;
        }
        int mid=(left+right)>>1;
        modify(now<<1,left,mid,findnum,changeval);
        modify(now<<1|1,mid+1,right,findnum,changeval);
        updata(now);
        return 0;
    }

    int ask(int now,int left,int right,int askl,int askr)
    {
        if((askr<left)||(askl>right))
        {
            return -inf;
        }
        if((askl<=left)&&(askr>=right))
        {
            return val[now];
        }
        int mid=(left+right)>>1;
        return std::max(ask(now<<1,left,mid,askl,askr),ask(now<<1|1,mid+1,right,askl,askr));
    }
};

struct data
{
    int start,end;
};

int n;
data d[maxn+10];

struct tree
{
    int pre[(maxn<<1)+10],now[maxn+10],son[(maxn<<1)+10],tot,val[(maxn<<1)+10];
    int fa[maxn+10],wson[maxn+10],deep[maxn+10],dfn[maxn+10],cnt,top[maxn+10],size[maxn+10];
    sigment_tree st;

    int mem()
    {
        memset(pre,0,sizeof pre);
        memset(now,0,sizeof now);
        memset(son,0,sizeof son);
        memset(val,0,sizeof val);
        memset(fa,0,sizeof fa);
        memset(wson,0,sizeof wson);
        memset(deep,0,sizeof deep);
        memset(dfn,0,sizeof dfn);
        memset(top,0,sizeof top);
        memset(size,0,sizeof size);
        tot=0;
        cnt=0;
        return 0;
    }

    int ins(int a,int b,int c)
    {
        tot++;
        pre[tot]=now[a];
        now[a]=tot;
        son[tot]=b;
        val[tot]=c;
        return 0;
    }

    int change(int pos,int val)
    {
        st.modify(1,1,n,dfn[pos],val);
        return 0;
    }

    int first_dfs(int u,int father)
    {
        deep[u]=deep[father]+1;
        fa[u]=father;
        size[u]=1;
        wson[u]=0;
        int j=now[u];
        while(j)
        {
            int v=son[j];
            if(v!=father)
            {
                first_dfs(v,u);
                size[u]+=size[v];
                if((!wson[u])||(size[v]>size[wson[u]]))
                {
                    wson[u]=v;
                }
            }
            j=pre[j];
        }
        return 0;
    }

    int second_dfs(int u,int father,int topfather)
    {
        cnt++;
        dfn[u]=cnt;
        top[u]=topfather;
        if(wson[u])
        {
            second_dfs(wson[u],u,topfather);
        }
        int j=now[u];
        while(j)
        {
            int v=son[j];
            if((v!=father)&&(v!=wson[u]))
            {
                second_dfs(v,u,v);
            }
            j=pre[j];
        }
        return 0;
    }

    int third_dfs(int u,int father,int pointval)
    {
        change(u,pointval);
        int j=now[u];
        while(j)
        {
            int v=son[j];
            if(v!=father)
            {
                third_dfs(v,u,val[j]);
                if(!(j&1))
                {
                    std::swap(d[(j+1)/2].start,d[(j+1)/2].end);
                }
            }
            j=pre[j];
        }
        return 0;
    }

    int ask(int x,int y)
    {
        int res=-inf;
        while(top[x]!=top[y])
        {
            if(deep[top[x]]<deep[top[y]])
            {
                std::swap(x,y);
            }
            res=std::max(st.ask(1,1,n,dfn[top[x]],dfn[x]),res);
            x=fa[top[x]];
        }
        if(deep[x]>deep[y])
        {
            std::swap(x,y);
        }
        res=std::max(st.ask(1,1,n,dfn[wson[x]],dfn[y]),res);
        return res;
    }
};

tree t;

int solve()
{
    scanf("%d",&n);
    t.mem();
    t.st.build(1,1,n);
    for(int i=1; i<n; i++)
    {
        int c;
        scanf("%d%d%d",&d[i].start,&d[i].end,&c);
        t.ins(d[i].start,d[i].end,c);
        t.ins(d[i].end,d[i].start,c);
    }
    t.first_dfs(1,0);
    t.second_dfs(1,0,1);
    t.third_dfs(1,0,-inf);
    while(1)
    {
        char s[10];
        int a,b;
        scanf("%s",s);
        if(s[0]=='C')
        {
            scanf("%d%d",&a,&b);
            t.change(d[a].end,b);
        }
        if(s[0]=='Q')
        {
            scanf("%d%d",&a,&b);
            printf("%d\n",t.ask(a,b));
        }
        if(s[0]=='D')
        {
            break;
        }
    }
    return 0;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值