HDU6686 Rikka with Travels

Posted zhanggengchen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU6686 Rikka with Travels相关的知识,希望对你有一定的参考价值。

题意

给一棵树,如果能选出两条没有交点的路径使得一条点数为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的主要内容,如果未能解决你的问题,请参考以下文章

HDU 5634 Rikka with Phi

HDU 5634 Rikka with Phi

hdu 6090 Rikka with Graph

HDU 6095: Rikka with Competition

图论(生成树):HDU 5631Rikka with Graph

HDU 5631 Rikka with Graph