QtreeⅠ

题意:https://vjudge.net/problem/SPOJ-QTREE

   带修路径查询最大边权

sol :树链剖分,之后每条重链就是一个连续的区间,拿线段树维护即可

    简单讲讲链剖吧.....就是把树边划分为轻重边,重边的定义是和siz最大的儿子之间的边

    通过两次dfs实现,可以证明重链(重边形成的链)不超过logn条

    直接上代码吧,复杂度O(nlogn^2)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=10010;
struct Edge { int x,y,val; } edge[Mx];
struct Tree { int l,r,val; } tree[4*Mx];
int n,cnt,dep[Mx],siz[Mx],fa[Mx],num[Mx],son[Mx],top[Mx];//top表示最近的重链父节点
int tot,nxt[2*Mx],head[Mx],ver[2*Mx],val[2*Mx];
void clear()
{
    memset(head,0,sizeof(head));
    memset(son,0,sizeof(son));
    cnt=0;tot=0;
}
inline void add(int x,int y,int z)
{
    tot++;
    nxt[tot]=head[x];
    ver[tot]=y;
    val[tot]=z;
    head[x]=tot;
}
//链剖
void dfs1(int u,int Fa,int Dep)
{
    dep[u]=Dep,siz[u]=1,son[u]=0,fa[u]=Fa;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=ver[i];
        if(v==Fa) continue;
        dfs1(v,u,Dep+1);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v]) son[u]=v;
    }
}
void dfs2(int u,int Top)
{
    top[u]=Top,num[u]=++cnt;
    if(son[u]) dfs2(son[u],Top);
    for(int i=head[u];i;i=nxt[i])
    {
        int v=ver[i];
        if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
    }
}
//线段树
void pushup(int x) { tree[x].val=max(tree[x<<1].val,tree[x<<1|1].val); }
void build(int l,int r,int v)
{
    tree[v].l=l;tree[v].r=r;
    if(l==r) { tree[v].val=val[l]; return ; }
    int mid=(l+r)>>1;
    build(l,mid,v*2); build(mid+1,r,v*2+1);
    pushup(v);
}
void update(int u,int v,int val)
{
    if(tree[u].l==tree[u].r) { tree[u].val=val; return ; }
    int mid=(tree[u].l+tree[u].r)/2;
    if(v<=mid) update(u*2,v,val);
    else update(u*2+1,v,val);
    pushup(u);
}
int query(int x,int l, int r)
{
    if(tree[x].l>=l&&tree[x].r<=r) return tree[x].val;
    int ans=0,mid=(tree[x].l+tree[x].r)/2;
    if(l<=mid) ans=max(ans,query(x<<1,l,r));
    if(r>mid) ans=max(ans,query(x<<1|1,l,r));
    return ans;
}
int solve(int u,int v)
{
    int ans=0,Top1=top[u],Top2=top[v];
    while(Top1!=Top2)
    {
        if(dep[Top1]<dep[Top2]) swap(Top1,Top2),swap(u,v);
        ans=max(ans,query(1,num[Top1],num[u]));
        u=fa[Top1];Top1=top[u];
    }
    if(u==v) return ans;
    if(dep[u]>dep[v]) swap(u,v);
    ans=max(ans,query(1,num[son[u]],num[v]));
    return ans;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        clear();
        scanf("%d",&n);
        for(int i=1,x,y,z;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            edge[i].x=x;edge[i].y=y;edge[i].val=z;
            add(x,y,z);add(y,x,z);
        }
        dfs1(1,0,1);dfs2(1,1);
        for(int i=1;i<n;i++)
        {
            if(dep[edge[i].x]<dep[edge[i].y]) swap(edge[i].x,edge[i].y);
            val[num[edge[i].x]]=edge[i].val;
        }
        build(1,cnt,1);
        while(1)
        {
            char s[200];scanf("%s",s);if(s[0]==‘D‘) break;
            int x,y; scanf("%d%d",&x,&y);
            if(s[0]==‘Q‘) printf("%d\n",solve(x,y));
            if (s[0]==‘C‘) update(1,num[edge[x].x],y);
        }
    }
   return 0;
}
时间: 2024-10-01 00:38:18

QtreeⅠ的相关文章

SPOJ QTREE 系列解题报告

题目一 : SPOJ 375 Query On a Tree http://www.spoj.com/problems/QTREE/ 给一个树,求a,b路径上最大边权,或者修改a,b边权为t. 1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 7 using namespace s

spoj qtree IV

2666. Query on a tree IV Problem code: QTREE4 You are given a tree (an acyclic undirected connected graph) with N nodes, and nodes numbered 1,2,3...,N. Each edge has an integer value assigned to it(note that the value can be negative). Each node has

QTREE - Query on a tree

QTREE - Query on a tree 题目链接:http://www.spoj.com/problems/QTREE/ 参考博客:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html 树链剖分入门题 代码如下(附注解): 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define lson (x<<1) 5 #d

SPOJ QTREE 树链剖分

375. Query on a tree Problem code: QTREE You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of

【COGS1672】【SPOJ375】QTREE

这是我的第一个边权链剖 COGS上和SPOJ有点不一样就是没有多组数据了本质还是一样的 我写的是COGS那个其实改一改就可以去SPOJ AC了= -= (可是我现在上不去SPOJ卧槽(╯‵□′)╯︵┻━┻) [题目描述] 一天机房的夜晚,无数人在MC里奋斗着... 大家都知道矿产对于MC来说是多么的重要,但由于矿越挖越少,勇士们不得不跑到更远的地方挖矿,但这样路途上就会花费相当大的时间,导致挖矿效率低下. cjj提议修一条铁路,大家一致同意. 大家都被CH分配了一些任务: zjmfrank201

SPOJ QTREE 375. Query on a tree

SPOJ Problem Set (classical) 375. Query on a tree Problem code: QTREE You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHA

SPOJ 375 QTREE - Query on a tree(树链剖分)

题目链接:http://www.spoj.com/problems/QTREE/en/ 题意:  一棵树 n 个节点,每条边上有权值,同时有两个操作: (1)更改操作:CHANGE i ti(把第 i 条边上的权值改为 ti). (2)查询操作:QUERY a b(查询 a 到 b 的路径上权值最大的边的权值). 思路(树链剖分): 看到这种区间查询的题想要用数据结构优化,提高时间效率一般会想到线段树.可是这次操作的对象并不是一组序列, 无法直接使用线段树.这时,我们可以做些转化:对树作树链剖分

【SPOJ】【Qtree】

QTREE - Query on a tree no tags You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3-N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th e

SPOJ QTREE系列 树上分治问题。

375.Query on a tree  [QTREE] 有两个操作: (1)修改第i条边的边权 (2)询问a到b路径上的边权最大值. 树链剖分入门题.树链剖分+线段树维护最大值.修改/查询均为O(log^2). 很懒,没有写. 913.Query on a tree II [QTREE2] 有两个操作: (1)询问a到b的距离. (2)询问a到b路径上的第k个点. 很容易想到倍增LCA. 路径上的第k个点,要么是a的第k个父亲,要么是b的第k'个父亲,同样可以倍增实现. 询问都是O(logn)

SPOJ - QTREE 375 Query on a tree 树链剖分+线段树

操作1:修改第k条边权. 操作2:询问两点间最大边权. 树链剖分,然后线段树维护最大值 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #inclu