SPOJ QTREE2 - Query on a tree II 倍增 LCA

SPOJ QTREE2 - Query on a tree II

Description

You are given a tree (an undirected acyclic connected graph) with N nodes, and edges numbered 1, 2, 3…N-1. Each edge has an integer value assigned to it, representing its length.

We will ask you to perfrom some instructions of the following form:

DIST a b : ask for the distance between node a and node b
or
KTH a b k : ask for the k-th node on the path from node a to node b 

Example:

N = 6
1 2 1 // edge connects node 1 and node 2 has cost 1
2 4 1
2 5 2
1 3 1
3 6 2

Path from node 4 to node 6 is 4 -> 2 -> 1 -> 3 -> 6
DIST 4 6 : answer is 5 (1 + 1 + 1 + 2 = 5)
KTH 4 6 4 : answer is 3 (the 4-th node on the path from node 4 to node 6 is 3)

Input
The first line of input contains an integer t, the number of test cases (t <= 25). 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, b of cost c (c <= 100000)
The next lines contain instructions "DIST a b" or "KTH a b k"
The end of each test case is signified by the string "DONE". 

There is one blank line between successive tests.

Output

For each “DIST” or “KTH” operation, write one integer representing its result
Print one blank line after each test.

Input:

1

6
1 2 1
2 4 1
2 5 2
1 3 1
3 6 2
DIST 4 6
KTH 4 6 4
DONE

Output:

5
3

题目分析

LCA模板题,虽然这道题是划分在树剖中,但是树剖我不会,就用LCA啦!距离很好处理,至于找第k个节点,我们用倍增条跳好了!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct arr{
    int nd,nx,co;
}bot[250000];
int n,m,mm,stepp,t,cnt;
int head[100005],fa[22][100005],dep[100005],dist[100005];
inline int read(){
    int x=0,w=1;char ch;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
    return x*w;
}
inline void initt(){
    cnt=0;mm=0;memset(head,0,sizeof(head));memset(dist,0,sizeof(dist));
    memset(bot,0,sizeof(bot)); memset(dep,0,sizeof(dep));memset(fa,0,sizeof(fa));
}
inline void add(int a,int b,int c)
 { bot[++cnt].nd=b; bot[cnt].nx=head[a]; bot[cnt].co=c; head[a]=cnt; }
void dfs(int u) {
    for(register int i=head[u];i;i=bot[i].nx){
        int v=bot[i].nd;
        if(!dep[v]) {
            dep[v]=dep[u]+1;mm=max(mm,dep[v]);
            fa[0][v]=u;
            dist[v]=dist[u]+bot[i].co;
            dfs(v);
        }
    }
}
inline void init(){
    for(register int j=1;j<=stepp;++j)
        for(register int i=1;i<=n;++i)
            fa[j][i]=fa[j-1][fa[j-1][i]];
}
inline int LCA(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    for(register int j=stepp;j>=0;--j)
        if(dep[fa[j][x]]>=dep[y]) x=fa[j][x];
    if(x==y) return x;
    for(register int j=stepp;j>=0;--j)
        if(fa[j][x]!=fa[j][y]) x=fa[j][x],y=fa[j][y];
    return fa[0][x];
}
inline int kfa(int u,int k) {
    for(register int i=0;i<=stepp;++i) 
        if(k>>i & 1) 
            u=fa[i][u];
    return u;
}
int main(){ 
    freopen("qtree2.in","r",stdin);
    freopen("qtree2.out","w",stdout);
    t=read();
    for(register int k=1;k<=t;++k) {
        n=read();initt();
        for(register int i=1;i<n;++i) {
            int u=read(),v=read(),c=read();
            add(u,v,c);add(v,u,c);
        }
        dep[1]=1;
        dfs(1);
        stepp=log2(mm);
        init();
        char ch[10];
        while(scanf("%s",ch)) {
            if(!strcmp(ch,"DONE")) break;
            if(ch[0]=='D') {
                int u=read(),v=read();
                int lca=LCA(u,v);
                printf("%d\n",dist[u]+dist[v]-2*dist[lca]);
            }
            else {
                int u=read(),v=read(),kk=read();
                int lca=LCA(u,v);
                int x=dep[u]-dep[lca];
                if(x + 1 >= kk)
                    printf("%d\n",kfa(u,kk-1));
            //如果在u到lca这条链上
                else
                    printf("%d\n",kfa(v,dep[v]+dep[u]-2*dep[lca]+1-kk));
            //如果在v到lca这条链上
            }
        }
    }
    return 0;
}

小结
打了半天(真的是一个上午啊)先打了一次,结果一直在SPOJ上RE,搞不懂.然后想起学长们说的一句话,是在改不了,就重打吧,然后就重打了一份代码,结果WA(smg).然后就拿网上的一道标称来对拍,后面拍出来发现,自己少打了一个”=”(天了咯,要是NOIP犯这种错误,可能会跳楼吧QWQ),还有一处就是把一句return u放在了循环里头(想死啊)以后这种情况还是得多避免发生,发生了就gg了

猜你喜欢

转载自blog.csdn.net/tangzhide123yy/article/details/81282598
今日推荐