SPOJ QTREE2 - Query on a tree II 倍增 LCA

9 篇文章 0 订阅
6 篇文章 0 订阅

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了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值