luogu 4886

点分治好题

统计距离正常点分治统计即可,我们只需考虑何时达到最优

有两种情况:

第一:代价最大的询问两个端点在不同的两个子树中

因为这种情况下,无论根向那个子树移动都会等价地增加到达另一个端点的代价,因此此时总代价已经达到最小

第二:代价最大的询问有多组,且这些点不在同一棵子树中

同情况一,如果我们把根偏向其中某一棵子树移动的话,那么一定会等价地增大另一端的代价,因此总代价已经达到最小

这样的话直接统计就好了

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
struct Edge
{
    int nxt;
    int to;
    int val;
}edge[200005];
int q[100005][2];
int siz[100005];
int rt,s;
int head[100005];
int maxp[100005];
int ans=0x3f3f3f3f;
bool vis[100005];
int dis[100005];
int bel[100005];
int ccl[100005];
int col=0,typ=0;
int cnt=1,maxx=0;
int n,m;
void add(int l,int r,int w)
{
    edge[cnt].nxt=head[l];
    edge[cnt].to=r;
    edge[cnt].val=w;
    head[l]=cnt++;
}
void get_rt(int x,int fx)
{
    siz[x]=1,maxp[x]=0;
    for(int i=head[x];i;i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(to==fx||vis[to])continue;
        get_rt(to,x);
        siz[x]+=siz[to];
        maxp[x]=max(maxp[x],siz[to]);
    }
    maxp[x]=max(maxp[x],s-siz[x]);
    if(maxp[x]<maxp[rt])rt=x;
}
void dfs(int x,int fx,int dep)
{
    dis[x]=dep;
    if(!fx)bel[x]=0;
    for(int i=head[x];i;i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(to==fx)continue;
        if(!fx)col++;
        bel[to]=col;
        dfs(to,x,dep+edge[i].val);
    }
}
int calc(int x)
{
    dis[x]=maxx=0,dfs(x,0,0);
    typ++;
    for(int i=1;i<=m;i++)
    {
        ccl[i]=0;
        if(dis[q[i][0]]+dis[q[i][1]]>maxx)maxx=dis[q[i][0]]+dis[q[i][1]],ccl[i]=++typ;
        else if(dis[q[i][0]]+dis[q[i][1]]==maxx)ccl[i]=typ;
    }
    return typ; 
}
void solve(int x)
{
    vis[x]=1;
    int k=calc(x);
    int ori=0;
    for(int i=1;i<=m;i++)
    {
        if((bel[q[i][0]]!=bel[q[i][1]])&&ccl[i]==k){ori=-1;break;}
        else if(ccl[i]==k&&!ori)ori=bel[q[i][0]];
        else if(ccl[i]==k)if(bel[q[i][0]]!=ori){ori=-1;break;}
    }
    ans=min(ans,maxx);
    for(int i=head[x];i;i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(vis[to])continue;
        if(bel[to]==ori)rt=0,s=siz[to],get_rt(to,x),solve(rt);
    }
}
inline int read()
{
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read(),z=read();
        add(x,y,z),add(y,x,z);
    }
    maxp[0]=0x3f3f3f3f;
    for(int i=1;i<=m;i++)q[i][0]=read(),q[i][1]=read();
    rt=0,s=n,get_rt(1,0),solve(rt);
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2019-07-08 21:39  lleozhang  Views(189)  Comments(0Edit  收藏  举报
levels of contents