1. 程式人生 > >E - Closest Common Ancestors

E - Closest Common Ancestors

sep NPU fin continue != roo seve sso ==

Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pair (u,v) the program determines the closest common ancestor of u and v in the tree. The closest common ancestor of two nodes u and v is the node w that is an ancestor of both u and v and has the greatest depth in the tree. A node can be its own ancestor (for example in Figure 1 the ancestors of node 2 are 2 and 5)

Input

The data set, which is read from a the std input, starts with the tree description, in the form:

nr_of_vertices
vertex:(nr_of_successors) successor1 successor2 ... successorn
...
where vertices are represented as integers from 1 to n ( n <= 900 ). The tree description is followed by a list of pairs of vertices, in the form:
nr_of_pairs
(u v) (x y) ...

The input file contents several data sets (at least one).
Note that white-spaces (tabs, spaces and line breaks) can be used freely in the input.

Output

For each common ancestor the program prints the ancestor and the number of pair for which it is an ancestor. The results are printed on the standard output on separate lines, in to the ascending order of the vertices, in the format: ancestor:times
For example, for the following tree:
技術分享圖片

Sample Input

5
5:(3) 1 4 2
1:(0)
4:(0)
2:(1) 3
3:(0)
6
(1 5) (1 4) (4 2)
(2 3)
(1 3) (4 3)

Sample Output

2:1
5:5
Hint
Huge input, scanf is recommended.

輸出公共節點的個數(抄的板子有毒..)輸入要特殊處理

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include <iomanip>
#include<cmath>
#include<float.h> 
#include<string.h>
#include<algorithm>
#define sf scanf
#define scf(x) scanf("%d",&x)
#define pf printf
#define prf(x) printf("%d\n",x)
#define mm(x,b) memset((x),(b),sizeof(x))
#include<vector>
#include<queue>
#include<map>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
typedef long long ll;
const ll mod=1e9+100;
const double eps=1e-8;
using namespace std;
const double pi=acos(-1.0);
const int inf=0xfffffff;
const int MAXN = 1010;
int rmq[2*MAXN];//rmq數組,就是歐拉序列對應的深度序列
struct ST
{
    int mm[2*MAXN];
    int dp[2*MAXN][20];//最小值對應的下標
    void init(int n)
    {
        mm[0] = -1;
        for(int i = 1;i <= n;i++)
        {
            mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
            dp[i][0] = i;
        }
        for(int j = 1; j <= mm[n];j++)
            for(int i = 1; i + (1<<j) - 1 <= n; i++)
                dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
    }
    int query(int a,int b)//查詢[a,b]之間最小值的下標
    {
        if(a > b)swap(a,b);
        int k = mm[b-a+1];
        return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
    }
};
//邊的結構體定義
struct Edge
{
    int to,next;
};
Edge edge[MAXN*2];
int tot,head[MAXN];

int F[MAXN*2];//歐拉序列,就是dfs遍歷的順序,長度為2*n-1,下標從1開始
int P[MAXN];//P[i]表示點i在F中第一次出現的位置
int cnt;

ST st;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v)//加邊,無向邊需要加兩次
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void dfs(int u,int pre,int dep)
{
    F[++cnt] = u;
    rmq[cnt] = dep;
    P[u] = cnt;
    for(int i = head[u];i != -1;i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre)continue;
        dfs(v,u,dep+1);
        F[++cnt] = u;
        rmq[cnt] = dep;
    }
}
void LCA_init(int root,int node_num)//查詢LCA前的初始化
{
    cnt = 0;
    dfs(root,root,0);
    st.init(2*node_num-1);
}
int query_lca(int u,int v)//查詢u,v的lca編號
{
    return F[st.query(P[u],P[v])];
}
bool root[MAXN];
int sum[MAXN];
int main()
{
    int n,m,num,x,u;
    while(~scf(n))
    {
        init();
        mm(sum,0);
        mm(root,true);
        rep(i,1,n+1)
        {
            sf("\t%d\t:\t(\t%d\t)",&u,&num);//一種方法
            while(num--)
            {
                int x;
                sf("\t%d\t",&x);
                addedge(u,x);
                addedge(x,u);
                root[x]=false;
            }
        }
        int temp;
        rep(i,1,n+1)
        {
            if(root[i])
            {
                temp=i;break;
            }
        }
        scf(m);
        LCA_init(temp,n);
        int v;
        while(m--)//另一種輸入方法
        {
            while(getchar()!=‘(‘) ;
                        scanf("%d%d",&u,&v);
                        while(getchar()!=‘)‘) ;
            sum[query_lca(u,v)]++;
        }
        rep(i,1,n+1)
        {
            if(sum[i])
            pf("%d:%d\n",i,sum[i]);
        }
    }
    return 0;
}

E - Closest Common Ancestors