码迷,mamicode.com
首页 > 其他好文 > 详细

HDU6686 Rikka with Travels

时间:2019-08-24 22:33:27      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:ace   other   要求   back   情况   front   因此   int   add   

题意

给一棵树,如果能选出两条没有交点的路径使得一条点数为x,一条点数为y,则(x,y)为合法对,求有多少合法对。

思路

其实我们需要求出对于每一个x其对应的最长的y,这样(x,1)....(x,y)都合法,也就是说x对答案贡献是y。因此我们讨论几种情况来更新每一个x的最大y。对于一棵树,可以分成一条直径和直径上每个点所连接的子树。这些子树有一些性质,第一子树根节点到最远的叶子节点的距离不大于子树根节点到直径两端较近一端的距离,否则直径会更长,第二子树的直径不大于直径,这个很显然。对于两条不相交的路径,第一种情况是在同一棵子树里,根据第二个性质,这种情况更新的答案不会优于选直径和除去直径后的直径,第二种情况是在不同的子树里,这种情况更新的答案不会优于选从直径两端不相交地走到两个根节点再分别在两个子树里走到离根节点最远的叶子结点。这个题太强了,我看了好几遍题解才明白。代码实现地也挺复杂。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 100000+10;

int n;
int pre[2*maxn],other[2*maxn];
int last[maxn],d[maxn],fr[maxn],len[maxn],mx[maxn],X[maxn],Y[maxn];
bool vis[maxn];
int tot;

void add(int x,int y)
{
    tot++;
    pre[tot]=last[x];
    last[x]=tot;
    other[tot]=y;
}

int bfs(int S)
{
    queue<int> que;
    que.push(S);
    for (int i=1;i<=n;i++) d[i]=fr[i]=0;
    d[S]=1;
    while (!que.empty())
    {
        int x=que.front();
        que.pop();
        for (int p=last[x];p;p=pre[p])
        {
            int q=other[p];
            if (!d[q])
            {
                d[q]=d[x]+1;
                fr[q]=x;
                que.push(q);
            }
        }
    }
    int T=S;
    for (int i=1;i<=n;i++)
    {
        if (d[i]>=d[T]) T=i;
    }
    return T;
}

int bfs1(int S,bool tag)
{
    queue<int> que;
    stack<int> sta;
    que.push(S);
    sta.push(S);
    d[S]=1;
    vis[S]=tag;
    while (!que.empty())
    {
        int x=que.front();
        que.pop();
        for (int p=last[x];p;p=pre[p])
        {
            int q=other[p];
            if (!d[q]&&!vis[q])
            {
                d[q]=d[x]+1;
                vis[q]=tag;
                que.push(q);
                sta.push(q);
            }
        }
    }
    int T=S,D=1;
    while (!sta.empty())
    {
        if (d[sta.top()]>=D) T=sta.top(),D=d[T];
        d[sta.top()]=0;
        sta.pop();
    }
    if (tag) return D;
    return T;
}

int dfs(int x,int fa)
{
    int ans=0;
    for (int p=last[x];p;p=pre[p])
    {
        int q=other[p];
        if (q!=fa&&!vis[q])
        {
            ans=max(ans,dfs(q,x));
        }
    }
    return ans+1;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) last[i]=len[i]=mx[i]=0,vis[i]=0;
        tot=0;
        for (int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        int P=bfs(1);
        int Q=bfs(P);
        vector<int> li;
        int tmp=Q;
        while (tmp)
        {
            li.push_back(tmp);
            vis[tmp]=1;
            tmp=fr[tmp];
        }
        for (int i=0;i<li.size();i++) len[li[i]]=dfs(li[i],0);
        for (int i=0;i<=n+1;i++) X[i]=Y[i]=0;
        for (int i=0;i<li.size();i++)
        {
            X[i]=i+len[li[i]];
            Y[i]=li.size()-i-1+len[li[i]];
        }
        for (int i=1;i<li.size();i++) X[i]=max(X[i],X[i-1]);
        for (int i=li.size()-2;i>=0;i--) Y[i]=max(Y[i],Y[i+1]);
        for (int i=1;i<li.size();i++)
        {
            mx[X[i-1]]=max(mx[X[i-1]],Y[i]);
            mx[Y[i]]=max(mx[Y[i]],X[i-1]);
        }
        for (int i=1;i<=n;i++) d[i]=0;
        for (int i=1;i<=n;i++)
        {
            if (!vis[i])
            {
                int P1=bfs1(i,0);
                int Q1=bfs1(P1,1);
                mx[li.size()]=max(mx[li.size()],Q1);
                mx[Q1]=li.size();
            }
        }
        LL ans=0;
        for (int i=li.size()-1;i>=1;i--) mx[i]=max(mx[i],mx[i+1]);
        for (int i=li.size();i>=1;i--) ans+=mx[i];
        printf("%lld\n",ans);
    }
    return 0;
}

HDU6686 Rikka with Travels

标签:ace   other   要求   back   情况   front   因此   int   add   

原文地址:https://www.cnblogs.com/zhanggengchen/p/11406181.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!