洛谷P4220 [WC2018]通道

题面:https://www.luogu.com.cn/problem/P4220
题意:给出三棵树,求出\(dis1(x,y)+dis2(x,y)+dis3(x,y)\)最大值。
题解:
首先,列举一下和深度、距离相关的可能用到的算法:
树剖,\(dis_x\)+\(dis_y\)-2\(dis_{lca(x,y)}\),虚树,点分治,边分治......
先考虑一个O(\(n^2\)logn)的算法:对三棵树树剖,枚举\(i\),\(j\),
\(dis_x\)+\(dis_y\)-2
\(dis_{lca(x,y)}\)求出答案。
这个算法用st表求lca可以做到O(\(n^2\))。
考虑优化这个算法。
肯定不能直接枚举\(i\),\(j\)了,考虑采用分治算法。
先考虑淀粉质。由于一个节点有多个子树,合并子树就显得十分麻烦,
而且还不能简单地采用容斥来排除子树内的贡献。
所以考虑对第一棵树进行边分治。
确定了分界边后,第一棵树的两点间距离可以直接通过一遍DFS处理出来。
设这条边为\((x,y)\),我们把两边的点分别染成黑白两色,设黑为\(B\),白为\(W\)
那么当前要处理的就是\(max(dis(x,i)+dis(x,y)+dis(y,j)+dis2(i,j)+dis3(i,j))\),i\(\in\){\(B\)},j\(\in\){\(W\)}。
\(dis(x,y)\)是个常量,可以扔到一边。再将dis2和dis3化为我们能求出的形式,即:
\(max(dis(x,i)+dis(y,j)+dis2(1,i)+dis2(1,j)-2dis2(1,lca(i,j))+dis3(1,i)+dis3(1,j)-2dis3(1,lca(i,j))\)
\(val[i]\)= \(dis1(x/y,i)+dis2(1,i)+dis3(1,i)\)(这里认为\(dis1[x]\)=\(dis1[y]\)=0),
那么要求的就是最大化\(val[i]+val[j]-2dis2(1,lca(i,j))-2dis3(1,lca(i,j))\)
由于要在点集时间内解决问题,不难想到在第二棵树上建虚树跑DP。
由于可以枚举lca,现在只有\(dis3(1,lca(i,j))\)这一个变量了。
这里有一个lemma:设点集\(S\)的最远点对为\(s1\),\(s2\),\(T\)的最远点对为\(t1\),\(t2\),
那么\(S->T\)的最远点对只可能是(\(s1,t1\)),(\(s1,t2\)),(\(s2,t1\)),(\(s2,t2\))中的一个。
这就提醒我们可以分别记录子树内黑白点的最远点对。这样,就可以用DP解决问题了。
最后,具体实现上有几个小细节:
1.最好用st表求lca,避免再多一个log;
2.多开struct,开三个namespace,以防止变量重名;
3.码量巨大,出问题最好手膜一组小数据试一试。
时间复杂度:O(n\(log^2\)n)
代码:

#include
using namespace std;
#define re register ll
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline ll
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
templateI read(D &res){
    res=0;register D g=1;register char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')g=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        res=(res<<3)+(res<<1)+(ch^48);
        ch=getchar();
    }
    res*=g;
}
#define T e[k].to
typedef pairpil;
ll n,X,Y;ll W,ans,Cent;
ll cnt1,cnt2,q1[404000],q2[404000],clr[404000];
ll val[404000];
namespace T3{
    struct E{
        ll to,nt;ll w;
    }e[202000];
    ll head[101000],tot;
    ll xu[202000],dep[202000],id[202000],lg[202000],f[202000][20];
    ll dis[101000];
    IN getmin(ll x,ll y){
        return dep[x]>1]+1;
        F(j,1,lg[tot]){
            F(i,1,tot-(1<y)swap(x,y);
        re len=lg[y-x+1];
        return getmin(f[x][len],f[y-(1<vec[101000];
    struct E{
        ll to,nt;ll w;
    }e[202000];
    ll head[101000],tot;
    ll xu[202000],dep[202000],id[202000],lg[202000],f[202000][20],in[202000],out[202000],dfn;
    ll dis[101000];
    ll top,st[404000];
    ll q[404000],num;
    struct Dat{
        ll x,y;ll dis;
        Dat(){x=y=dis=0;}
        Dat(const ll &_x,const ll &_y){x=_x;y=_y;dis=T3::ques_dis(x,y);}
        Dat(const ll &_x,const ll &_y,const ll &_w){x=_x;y=_y;dis=_w;}
        friend bool operator < (Dat a,Dat b){return a.dis>1]+1;
        F(j,1,lg[tot]){
            F(i,1,tot-(1<y)swap(x,y);
        re len=lg[y-x+1];
        return getmin(f[x][len],f[y-(1<y?x:y;
    }
    I solve(){
        top=0;
        //cout<0)q[++num]=st[i];
            else {
                num--;if(!num)continue;
                X=q[num+1],Y=q[num];
                //cout<vec[101000];
    ll num[101000];
    struct E{
        ll to,nt;ll w;bool v;
    }e[808000];
    ll head[404000],tot,cnt;
    ll siz[404000],V[404000],maxi;
    I add(ll x,ll y,ll w){
        //cout<<"!"<

你可能感兴趣的:(洛谷P4220 [WC2018]通道)