BZOJ 1791-基环树DP

题目链接:https://darkbzoj.cf/problem/1791

 

解题思路:

如果题目给的是一棵树,那么就跟简单了,直接搞个DP求出树上最长两点路径就OK了:

dp[i]表示以i为子树的节点到i的最长距离。那么有

ans = max(ans,dp[u]+dp[v]+1);

dp[u] = max(dp[u],dp[v]+1);其中v是u的子节点。

所以我们可以把这个基环树看做普通树来做,以环为中心,环上的每一个节点都能伸出一颗以该节点为根的树,那么这些树就可以用普通树dp来做,最后环上的每个节点都会得到一个dp[i]值,我们看做它们的点值d[i]。

最后的问题就是变为环上任意两点的和为d[j]+d[i]+sum[j]-sum[i],sum[j]-sum[i]表示它们环上的距离。

d[i]-sum[i]可以用单调队列维护。因为是环,所以我们把环复制两遍变成链来做。

 

#include 
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int mx = 1e6 + 10; 
int n,head[mx],tot,q[mx<<1],beg,last;
ll dep[mx<<1],ret,sum[mx<<1];
bool vis[mx],loop[mx],in[mx];
pair  st[mx],g[mx];
struct node
{
    int v,w;
    int nxt;
}edge[mx<<1];
void AddEdge(int u,int v,int w)
{
    edge[tot] = {v,w,head[u]};
    head[u] = tot++;
    edge[tot] = {u,w,head[v]};
    head[v] = tot++; 
}
void dfs(int x,int fa)
{
    if(in[x]){
        beg = last-1;
        while(g[beg].fi!=x) beg--;
        for(int i=0;i=dep[q[r-1]]-sum[q[r-1]]) r--;
                q[r++] = j;
                while(l!=r&&q[l]<=j-last+1)  l++;
            }
            ans += ret;
        }
    } 
    printf("%lld\n",ans);
    return 0;
} 

 

你可能感兴趣的:(DP,图论,单调性)