SPOJ:Ada and Orange Tree (LCA+Bitset)

Ada the Ladybug lives near an orange tree. Instead of reading books, she investigates the oranges. The oranges on orange tree can be in up to 5*50 Shades of Orange. She walks from orange to orange, examining different properties of orange tree. The oranges are connected by branches. There is more oranges then branches, yet it is still possible to get from any orange to any other orange [through branches]. The tree is rooted.

Ada has many questions in following form: She goes from orange A to orange B (by shortest path) and is interested in total number different Shades of Orange among all subtrees of all edges on shortest path.

Input

The first line of input consists of 1 ≤ T ≤ 100, the number of test-cases.

The first line of each test case contains three integers 1 ≤ N, Q ≤ 4.5*105, 0 ≤ R < N, the number of oranges, the number of questions and number of root.

Next line contains integers 1 ≤ Si ≤ 250, the shade of orange of orange i.

Next N-1 lines contains two integers 0 ≤ I, J < N, I ≠ J , the numbers of oranges which are connected by branch.

Next Q lines contains two integers 0 ≤ A, B < N, the path Ada is interested about.

The sum of all N and all Q among all test-cases won‘t exceed 106

Output

For each question answer the number of shades in all subtrees of all nodes on shortest path from A to B.

Example Input

1
10 7 1
1 2 1 4 5 6 6 8 9 9
0 9
9 3
3 4
4 6
4 5
4 8
1 3
1 2
2 7
4 4
8 6
0 6
7 0
7 2
0 0
2 3

Example Output

3
3
5
7
2
1
7

题意:给定一棵树,每个节点有一种颜色的橘子;Q次询问,每次询问,给出u、v,回答u到v的最短路径上的节点的子树一共有多少种颜色的橘子。

思路:其实就是问最小公共祖先LCA的子树的颜色种类。因为颜色只有250种,我们DFS时就用Bitset记录子树的颜色种类数。

#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=450010;
int Laxt[maxn],Next[maxn<<1],To[maxn<<1];
int fa[maxn][20],dep[maxn],N,Q,rt,cnt;
bitset<251>S[maxn];
void init()
{
    for(int i=1;i<=N;i++) S[i].reset();
    for(int i=1;i<=N;i++) Laxt[i]=0;
    memset(Laxt,0,sizeof(Laxt));
    cnt=0;
}
void add(int u,int v){
    Next[++cnt]=Laxt[u];
    Laxt[u]=cnt;
    To[cnt]=v;
}
void dfs(int u,int f){
    fa[u][0]=f; dep[u]=dep[f]+1;
    for(int i=Laxt[u];i;i=Next[i]){
        if(To[i]!=f){
          dfs(To[i],u);
          S[u]|=S[To[i]];
        }
    }
}
void RMQ()
{
    for(int i=1;i<20;i++)
     for(int j=1;j<=N;j++)
      fa[j][i]=fa[fa[j][i-1]][i-1];
}
int LCA(int u,int v){
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=19;i>=0;i--)
      if(dep[fa[u][i]]>=dep[v])
        u=fa[u][i];
    if(u==v) return u;
    for(int i=19;i>=0;i--)
      if(fa[u][i]!=fa[v][i])
        u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}
int main()
{
    int T,x,u,v,lca;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&N,&Q,&rt);
        rt++; init();
        for(int i=1;i<=N;i++){
            scanf("%d",&x);
            S[i][x]=1;
        }
        for(int i=1;i<N;i++){
            scanf("%d%d",&u,&v);
            u++; v++;
            add(u,v); add(v,u);
        }
        dfs(rt,0); RMQ();
        while(Q--){
            scanf("%d%d",&u,&v);
            u++; v++;
            lca=LCA(u,v);
            printf("%d\n",S[lca].count());
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/hua-dong/p/8921033.html

时间: 2024-11-08 21:38:38

SPOJ:Ada and Orange Tree (LCA+Bitset)的相关文章

bzoj 2588: Spoj 10628. Count on a tree LCA+主席树

2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数

BZOJ 2588: Spoj 10628. Count on a tree 主席树+lca

2588: Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组询问.

【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA

[BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组

BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2588 Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Inp

BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一

HDU 4836 The Query on the Tree lca || 欧拉序列 || 动态树

lca的做法还是很明显的,简单粗暴, 不过不是正解,如果树是长链就会跪,直接变成O(n).. 最后跑的也挺快,出题人还是挺阳光的.. 动态树的解法也是听别人说能ac的,估计就是放在splay上剖分一下,做法还是比较复杂的,,, 来一发lca: #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #inc

hdu 4929 Another Letter Tree(LCA+DP)

hdu 4929 Another Letter Tree(LCA+DP) 题意:有一棵树n个节点(n<=50000),树上每个节点上有一个字母.m个询问(m<=50000),每次询问一个(a,b),问a节点到b节点的点不重复路径组成的字符串中子序列为s0的情况有多少种,s0长度小于等于30(注意s0是已经给定的,而不是每次询问都会给出一个新的). 解法:一个很直观的想法,求出lca(设其为w)后,枚举x,求出a到w的路径上,能匹配s0的x长度前缀的情况有多少种,令其为c[x].再求出b到w的路

spoj 375. Query on a tree 【树链剖分--插点问线 】

题目:spoj 375. Query on a tree 题意:题意很清晰,就是给你一颗树,每两点之间有权值,然后改变一些权值,问一条路径上的最大值. 分析:入门题目,直接套树链模板 AC代码: #include <cstdio> #include <algorithm> #include <iostream> #include <string.h> using namespace std; const int N = 10010; #define Del(

PJOI PKU Campus 2011 B:A Problem about Tree LCA 求任意点x为根的y的父节点

题目链接:点击打开链接 题意:给定n个点 m个询问 下面n-1行给定一棵树 m个询问 x y 问把树转成以x为根 y的父节点是谁 第一种情况lca==y那就是x的第 dep[x] - dep[y] -1 父亲,依次向上爬山坡,利用倍增的二进制加速. 第二种就是Father[y]; #include"cstdio" #include"iostream" #include"queue" #include"algorithm" #i