zoukankan      html  css  js  c++  java
  • SPOJ375Query on a tree I(树剖+线段树)(询问边)

    ι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 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 N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between ab 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.

    Example

    Input:
    1
    
    3
    1 2 1
    2 3 2
    QUERY 1 2
    CHANGE 1 3
    QUERY 1 2
    DONE
    
    Output:
    1
    3

    题意:

    对于一棵树,有如下两种操作;

    • 询问u,v两点间的最短路上权值最大的边。
    • 更改某条边的权值。

    思路:

    树剖基础题,大家都会,而我刚刚学,所以就不啰嗦了。

    如果是更新点,查询点,可能好写点。而这里是对边进行处理,写半天把自己搅混了。。。

    代码里是这样处理的:

    • 对于每条边的两个顶点u,v,距离root远的是u,不然交换即可。假设这条边是i,用tid[u]表示这条边在线段树中对应的位置。即tid x表示x和父亲这条边在线段树中的位置。用时间戳tim++保证了root一下的x才有对应的tid;
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    const int maxn=20010;
    using namespace std;
    int e[maxn][3];
    int dpt[maxn],son[maxn],fa[maxn];
    int Laxt[maxn],Next[maxn],To[maxn],cnt;
    int sz[maxn],tid[maxn],top[maxn],tim;//树剖 
    int Max[maxn],Rank[maxn],n;//线段树 
    //tid[v]表示v与其父亲节点的连边在线段树中的位置 即time'id
    struct TC
    {
        int lowbit(int x) { return x&(-x);}
        void init()
        {
            cnt=1; tim=0;
            memset(Laxt,0,sizeof(Laxt));
            memset(Max,0,sizeof(Max));
            memset(son,0,sizeof(son));
        }
        void add_edge(int u,int v)
        {
            Next[++cnt]=Laxt[u]; 
            Laxt[u]=cnt; To[cnt]=v;
        }
        int dfs1(int u,int pre)//得到dpt,fa,son,sz 
        {
            fa[u]=pre;dpt[u]=dpt[pre]+1;sz[u]=1;
            for(int i=Laxt[u];i;i=Next[i]){
                int v=To[i];
                if(v!=pre){
                    dfs1(v,u); sz[u]+=sz[v];
                    if(!son[u]||sz[v]>sz[son[u]]) son[u]=v;
                }
            }
        }
        void dfs2(int u,int Top)//得到边在线段树中的位置。 
        {
            top[u]=Top; tid[u]=tim++; Rank[tid[u]]=u;//是tim++,而不是++tim,从而把root排除,弱保存点是后者 
            if(!son[u]) return ;
            dfs2(son[u],Top); 
            for(int i=Laxt[u];i;i=Next[i]){
                int v=To[i];
                if(v!=fa[u]&&v!=son[u]) {
                     dfs2(v,v);//这里不再是Top了,换链了。 
                }
            }
        }
        int update(int Now,int L,int R,int pos,int num)
        {
            if(L==pos&&R==pos) return Max[Now]=num; 
            int Mid=(L+R)>>1;//下面注意不要丢掉return,WA了两发。不然多写个push_up也可以。 
            if(pos<=Mid) return Max[Now]=max(update(Now<<1,L,Mid,pos,num),Max[Now<<1|1]);
            else return Max[Now]=max(update(Now<<1|1,Mid+1,R,pos,num),Max[Now<<1]);
        }
        void Make_tree()
        {
            int u,v;
            for(int i=1;i<n;i++){
                scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
                add_edge(e[i][0],e[i][1]); 
                add_edge(e[i][1],e[i][0]);
            }
            dfs1(1,0);  
            dfs2(1,1);
            for(int i=1;i<n; i++){//单点更新建树 
                if(dpt[e[i][0]]>dpt[e[i][1]]) swap(e[i][0],e[i][1]);
                update(1,1,n-1,tid[e[i][1]],e[i][2]);
            }
        } 
        int get_max(int Now,int L,int R,int l,int r)
        {
            if(L>=l&&R<=r) return Max[Now];
            int Mid=(L+R)>>1;
            if(Mid>=r) return get_max(Now<<1,L,Mid,l,r);
            else if(Mid+1<=l) return get_max(Now<<1|1,Mid+1,R,l,r);
            else return max(get_max(Now<<1,L,Mid,l,r),get_max(Now<<1|1,Mid+1,R,l,r));
        }
        void Query()
        {
            int u,v; scanf("%d%d",&u,&v);
            int f1=top[u],f2=top[v];
            int ans=0;
            while(f1 != f2){
               if(dpt[f1] < dpt[f2]){
                  swap(f1,f2); swap(u,v);
               }
               ans=max(ans,get_max(1,1,n-1,tid[f1],tid[u]));
               u=fa[f1]; f1=top[u];
            }
            if(u!=v){
                if(dpt[u]>dpt[v]) swap(u,v);
                ans=max(ans,get_max(1,1,n-1,tid[son[u]],tid[v])); 
            }
            printf("%d
    ",ans);
        }
        void Change()
        {
            int u,w; scanf("%d%d",&u,&w);
            update(1,1,n-1,tid[e[u][1]],w);
        }
    }Tc;
    int main()
    {
        int T; char c[10];
        scanf("%d",&T);
        while(T--){
            Tc.init();
            scanf("%d",&n);
            Tc.Make_tree();
            while(~scanf("%s",&c)){
                if(c[0]=='D') break;
                else if(c[0]=='Q') Tc.Query();
                else Tc.Change();
            }
        } return 0;
    }
  • 相关阅读:
    如何使得事务使用同一个连接对象Connection呢?
    快速使用上咱的ideal的快捷键小技巧
    委托模式的理解:
    克隆、深拷贝与浅拷贝区别
    mysql存储过程与事务
    sql异常处理以及sql异常处理优先级
    Mysql 遇到神奇的“本次本客户端效现象”,数据库并未被改变 + 神奇“卡顿现象”
    网络传输时既有管道流(PipedInputStream 与 PipedOutStream)又有序列化对象、反序列化对象(ObjectOutputStream与 ObjectInputStream),还有在集合中、流中都有的身影的Properties究竟是何方神物?我们该怎么选择呢?
    数据库设计的三大范式
    实体类(VO,DO,DTO,PO)的划分
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8059856.html
Copyright © 2011-2022 走看看