hdu4916 Count on the path

 2014 Multi-University Training Contest 5 F題。

題目大意:給定一顆n個節點的樹,q個查詢,每次查詢輸入兩個端點(u,v),代表樹上一條從u->v的路徑,求刪掉這條路徑上的點後,剩下的點中編號最小的點。

題目分析:可以這樣想象:(1)我們以1這個節點爲根,刪掉根節點後形成若干個聯通分量,很顯然若路徑中的兩個端點在刪掉根節點後還在同一個聯通分量中,那麼所求結果必然爲1。這個可在預處理後O(1)實現(2)若兩個端點不在同一個聯通分量中,那麼必然經過根節點,此時若純暴力則時間複雜度可達O(n*q)之大,題目數據量非常大,必然死掉。 官方的題解給了做題的方向,可以用樹形DP的思想,預處理求出每個節點的f[]值,f[u]代表從u到他所屬的根節點(刪除1之後的)除去路徑上的點後編號最小的點值。

如下圖所示,所求的值f[2]=4,f[3]=7,f[4]=5,f[5]=6,f[7]=8,f[8]=7,f[9]=8;

2所對應的根節點爲2,f[2]=min(與2同屬於一個聯通分量且不在2到根節點的鏈上的,2以下的節點中編號最小的);

求出所有的f[]值後,還需知道各個聯通分量中編號最小的點,因爲當根節點1的兒子節點有多個,即有多個聯通分量時 ,兩個端點分屬兩個聯通分量,最小值可能出現在別的聯通分量中,但f[]值沒有考慮到。 則我們需要保存編號最小的三個聯通分量。

比較繞口,過後補上圖解。


#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<queue>
struct node
{
    int u,parent;
    node(){}
    node(int x,int y)
    {
        u=x,parent=y;
    }
};
using namespace std;
const int maxn = 1000010;
stack<int  >S;
queue<node >Q;
int pp[maxn];
int n,q,ecnt=0;
int next[maxn*2],e[maxn*2],head[maxn];
int cnt[maxn],f[maxn],x[5],y[5],other[maxn];
void addedge(int u,int v)
{
    e[ecnt]=v;
    next[ecnt]=head[u];
    head[u]=ecnt++;
    e[ecnt]=u;
    next[ecnt]=head[v];
    head[v]=ecnt++;
}
void dfs(int u,int fa)
{
    f[u]=fa;
    S.push(u);
    while (!S.empty())
    {
        u=S.top();
        int flag=0;
        for (int i=head[u];i!=-1;i=next[i])
        {
            int v=e[i];
            if (!f[v])
            {
                f[v]=fa;
                S.push(v);
                flag=1;
                break;
            }
        }
        if (!flag)
        {
            S.pop();
            if (!S.empty())
            {
                int v=u;
                u=S.top();
                cnt[u]=min(v,cnt[u]);
                cnt[u]=min(cnt[u],cnt[v]);
            }
        }
    }
}
void bfs(int u,int parent)
{
    Q.push(node(u,parent));
    while (!Q.empty())
    {
        int x1=n+1,x2=n+1,y1=n+1,y2=n+1;
        node tem=Q.front();
        Q.pop();
        u=tem.u;
        parent=tem.parent;
        for (int i=head[u];i!=-1;i=next[i])
        {
            int v=e[i];
            if (v!=parent)
            {
                Q.push(node(v,u));
                int yy=min(cnt[v],v);
                if (yy<y1)
                {
                    y2=y1;
                    x2=x1;
                    y1=yy;
                    x1=v;
                }
                else if (yy<y2)
                {
                    y2=yy;
                    x2=v;
                }
            }
        }
        for (int i=head[u];i!=-1;i=next[i])
        {
            int v=e[i];
            if (v==u)
                continue;
            other[v]=other[u];
            if (v!=x1)
            {
                other[v]=min(other[v],y1);
            }
            else
            {
                other[v]=min(other[v],y2);
            }
        }
    }
    return ;
}
inline void scan(int &n)
{
    char cc;
    for (; cc = getchar(), cc<'0' || cc>'9';);
    n = cc - '0';
    for (; cc = getchar(), cc >= '0'&&cc <= '9';)
        n = n * 10 + cc - '0';
}
int main()
{
    while (scanf("%d%d",&n,&q)!=EOF)
    {
        int i,j,u,v,prex=0;
        ecnt=0;
        for (i=1;i<=n;i++)
        {
            head[i]=-1;
            f[i]=0;
            cnt[i]=n+1;
            other[i]=n+1;
        }
        for (i=1;i<n;i++)
        {
//            scanf("%d%d",&u,&v);
            scan(u);
            scan(v);
            addedge(u,v);
        }
        f[1]=1;
        cnt[1]=n+1;
        x[0]=x[1]=x[2]=0;
        y[0]=y[1]=y[2]=n+1;
        for (i=head[1];i!=-1;i=next[i])
        {
            dfs(e[i],e[i]);
        }
        for (i=head[1];i!=-1;i=next[i])
        {
            bfs(e[i],1);
            int fa=min(cnt[e[i]],e[i]);
            if (fa<y[0])
            {
                y[2]=y[1];
                y[1]=y[0];
                y[0]=fa;
                x[2]=x[1];
                x[1]=x[0];
                x[0]=e[i];
            }
            else if (fa<y[1])
            {
                y[2]=y[1];
                y[1]=fa;
                x[2]=x[1];
                x[1]=e[i];
            }
            else if (fa<y[2])
            {
                y[2]=fa;
                x[2]=e[i];
            }
        }
        for (i=2;i<=n;i++)
        {
            cnt[i]=min(other[i],cnt[i]);
        }
        for (i=0;i<q;i++)
        {
//            scanf("%d%d",&u,&v);
            scan(u);
            scan(v);
            u^=prex;
            v^=prex;
            if (f[u]==f[v]&&(u!=1&&v!=1))
            {
                printf("1\n");
                prex=1;
            }
            else
            {
                int tot=min(cnt[u],cnt[v]);
                if (tot>y[0]&&(x[0]!=f[u]&&x[0]!=f[v]))
                {
                    tot=y[0];
                }
                else if (tot>y[1]&&(x[1]!=f[u]&&x[1]!=f[v]))
                {
                    tot=y[1];
                }
                else if (tot>y[2])
                {
                    tot=y[2];
                }
                prex=tot;
                printf("%d\n",tot);
            }
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章