题面: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<<"!"<