HDU 5266 pog loves szh III (LAC)

来源:互联网 发布:3ds跨区软件 编辑:程序博客网 时间:2024/05/10 22:57

问题描述
pog在与szh玩游戏,首先pog在纸上画了一棵有根树,这里我们定义1为这棵树的根,然后szh在这棵树中选了若干个点,想让pog帮忙找找这些点的最近公共祖先在哪里,一个点为S的最近公共祖先当且仅当以该点为根的子树包含S中的所有点,且该点深度最大。然而,这个问题是十分困难的,出于szh对pog的爱,他决定只找编号连续的点,即l i  ~r i  
输入描述
若干组数据(不超过3 n10000 Q10000 )。每组数据第一行一个整数n(1n300000) ,表示树的节点个数。接下来n1 行,每行两个数A i B i  ,表示存在一条边连接这两个节点。接下来一行一个数Q(1Q300000) ,表示有Q 组询问。接下来Q行每行两个数l i ,r i (1lirin) ,表示询问编号为l i  ~r i  的点的最近公共祖先。
输出描述
对于每组的每个询问,输出一行,表示编号为li~ri的点的最近公共祖先的编号。
输入样例
51 21 33 44 551 22 33 43 51 5
输出样例
11331


思路:

做这题的方法有很多。下面给出2种解法。1:维护一个跳表,表示编号为i ~i+2 j 1 的LCA,注意在这里求LCA必须用O(1) 的做法才能通过所有数据。可以转换为RMQ,每次查询时只需查询两个数的LCA即可。2:考虑dfs序,通过在简单的证明可知L~R的LCA为L ~R 中dfs序较小的那个位置与dfs序较大的那个位置的LCA。因此只要通过st表处理L~R最大dfs序与最小dfs序的编号即可。
方法一:
#include<cstdio>#include<iostream>#include<cstring>#include<queue>#include<algorithm>using namespace std;#pragma comment(linker, "/STACK:1024000000,1024000000")const int N = 300000+1000;int Q,n;int head[N];struct Edge{    int v,nxt;}es[N<<1];int cnt;inline void add_edge(int u,int v){    es[cnt].v=v;    es[cnt].nxt=head[u];    head[u]=cnt++;    es[cnt].v=u;    es[cnt].nxt=head[v];    head[v]=cnt++;}int index;int vs[N*2],id[N],dep[N];int lca[N*2][20];int minn[N][20];int maxn[N][20];void dfs(int u,int fa,int h){    id[u]=++index;    vs[index]=u;    dep[u]=h;    for(int i=head[u];~i;i=es[i].nxt)    {        int v=es[i].v;        if(v==fa)continue;        dfs(v,u,h+1);        vs[++index]=u;    }}int mm[2*N+100];void ini(){    memset(head,-1,sizeof(head));    cnt=index=0;}int main(){    mm[0]=-1;    for(int i=1;i<=2*N;i++) mm[i]= (((i-1)&i)==0)? mm[i-1]+1:mm[i-1];    while(~scanf("%d",&n))    {        ini();        for(int i=1;i<n;i++)        {            int u,v;            scanf("%d%d",&u,&v);            add_edge(u,v);        }        dfs(1,1,0);        for(int i=1;i<=index;i++) lca[i][0]=vs[i];        for(int j=1;j<=20;j++)            for(int i=1;i+(1<<j)-1<=index;i++)            {                int a=lca[i][j-1],b=lca[i+(1<<(j-1))][j-1];                lca[i][j] = dep[a]<dep[b] ? a:b;            }        for(int i=1;i<=n;i++) minn[i][0]=maxn[i][0]=id[i];        for(int j=1;j<=20;j++)            for(int i=1;i+(1<<j)-1<=n;i++)            {                minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);                maxn[i][j]=max(maxn[i][j-1],maxn[i+(1<<(j-1))][j-1]);            }        scanf("%d",&Q);        for(int i=1;i<=Q;i++)        {            int l,r;            scanf("%d%d",&l,&r);            int k=mm[r-l+1];            int L=min(minn[l][k],minn[r-(1<<k)+1][k]);            int R=max(maxn[l][k],maxn[r-(1<<k)+1][k]);            k=mm[R-L+1];            int a=lca[L][k],b=lca[R-(1<<k)+1][k];            int ans = dep[a]<dep[b]? a:b;            printf("%d\n",ans);        }    }    return 0;}


方法二:(防止爆栈就换成bfs)
#pragma comment(linker, "/STACK:1024000000,1024000000")#include<cstdio>#include<iostream>#include<cstring>#include<queue>#include<algorithm>using namespace std;const int N = 300000+1000;const int DEG  = 20;int Q,n;int pa[N][20];int dep[N];int head[N];struct Edge{    int v,nxt;}es[N<<1];int cnt;inline void add_edge(int u,int v){    es[cnt].v=v;    es[cnt].nxt=head[u];    head[u]=cnt++;    es[cnt].v=u;    es[cnt].nxt=head[v];    head[v]=cnt++;}/*void bfs(int root){    queue<int>q;    dep[root]=0;    pa[root][0]=root;    q.push(root);    while(!q.empty())    {        int u=q.front();        q.pop();        for(int i=1;i<DEG;i++)            pa[u][i]=pa[pa[u][i-1]][i-1];        for(int i=head[u];~i;i=es[i].nxt)        {            int v=es[i].v;            if(v==pa[u][0]) continue;            pa[v][0]=u;            dep[v]=dep[u]+1;            q.push(v);        }    }}*/void dfs(int u,int fa,int h){    dep[u]=h;    pa[u][0]=fa;    for(int i=1;i<DEG;i++) pa[u][i]=pa[pa[u][i-1]][i-1];    for(int i=head[u];~i;i=es[i].nxt)    {        int v=es[i].v;        if(v!=fa) dfs(v,u,h+1);    }}int dp[N][20];int LCA(int u,int v){    if(dep[u]>dep[v]) swap(u,v);    for(int det=dep[v]-dep[u],i=0;det;det>>=1,i++)        if(det&1) v=pa[v][i];    if(u==v) return u;    for(int i=DEG-1;i>=0;i--)        if(pa[u][i]!=pa[v][i]) v=pa[v][i],u=pa[u][i];    return pa[u][0];}int mm[N];void ini(){    memset(head,-1,sizeof(head));    cnt=0;}int main(){    mm[0]=-1;    for(int i=1;i<=N-1;i++)mm[i]= (((i-1)&i)==0)? mm[i-1]+1:mm[i-1];    while(~scanf("%d",&n))    {        ini();        for(int i=1;i<n;i++)        {            int u,v;            scanf("%d%d",&u,&v);            add_edge(u,v);        }        dfs(1,1,0);        for(int i=1;i<=n;i++) dp[i][0]=i;        for(int j=1;j<=20;j++)            for(int i=1;i+(1<<j)-1<=n;i++)                dp[i][j]=LCA(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);        scanf("%d",&Q);        for(int i=1;i<=Q;i++)        {            int l,r;            scanf("%d%d",&l,&r);            int k=mm[r-l+1];            int ans=LCA(dp[l][k],dp[r-(1<<k)+1][k]);            printf("%d\n",ans);        }    }    return 0;}


0 0