original link - http://acm.hdu.edu.cn/showproblem.php?pid=6686
题意:
给出一棵树,两条路径不相交定义为不能有重复点,一个有向关系<p1,p2><p1,p2><p1,p2>,表示两天不相交的路径的点数为p1,p2p1,p2p1,p2,求有多少对。
解析:
要维护以下变量:
- 子树内与根相连的链的第一长,第二长和第三长,记为mx,mxx,mxxxmx,mxx,mxxxmx,mxx,mxxx。
- 子树中的最长链,记为sizsizsiz
那么我们考虑向下dfsdfsdfs。传参有两个:
- 与子树不相交的,最长的链,记为upupup
- 与子树不相交的,以父亲为一端的链up2up2up2
那么做到一个点,维护的答案就是<up,siz><up,siz><up,siz>。
之所以需要up2up2up2是因为向下搜索后,upupup可能从up2up2up2加上一条其他链得来。
mx,mxx,mxxxmx,mxx,mxxxmx,mxx,mxxx是因为upupup可能从其他两条链得来。
还要一种情况,upupup从其他分支的sizsizsiz得来。
up2up2up2的维护就是原来的up2+1up2+1up2+1,或是其他的链。
最后维护答案就是<x,y><x,y><x,y>,在线段树更新[1,x],[1,y][1,x],[1,y][1,x],[1,y]的最大值,最后的答案为所有位置的最大值之和。
代码:
/*
* Author : Jk_Chen
* Date : 2019-08-19-20.17.35
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define debug(i) printf("D_# %d\n",i)
const LL mod=1e9+7;
const int maxn=1e5+9;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
/*_________________________________________________________head*/
int n;
int tr[maxn<<2];
int laz[maxn<<2];
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
void down(int rt){
if(laz[rt]){
laz[ls]=max(laz[ls],laz[rt]);
laz[rs]=max(laz[rs],laz[rt]);
tr[ls]=max(tr[ls],laz[rt]);
tr[rs]=max(tr[rs],laz[rt]);
laz[rt]=0;
}
}
void update(int rt,int l,int r,int L,int R,int val){
if(l>=L&&r<=R){
tr[rt]=max(tr[rt],val);
laz[rt]=max(laz[rt],val);
return;
}
down(rt);
if(L<=mid)update(ls,l,mid,L,R,val);
if(R>mid)update(rs,mid+1,r,L,R,val);
tr[rt]=max(tr[ls],tr[rs]);
}
int query(int rt,int l,int r,int pos){
if(l==r){
return tr[rt];
}
down(rt);
if(pos<=mid)return query(ls,l,mid,pos);
return query(rs,mid+1,r,pos);
}
#define rep_e(i,p,u) for(int i=head[p],u=to[i];i;i=nex[i],u=to[i])
int head[maxn],to[maxn<<1],nex[maxn<<1],now;
void add(int a,int b){
nex[++now]=head[a];head[a]=now;to[now]=b;
}
void init_edge(){
memset(head,0,sizeof head);
now=0;
}
int mx[maxn],mxx[maxn],mxxx[maxn],siz[maxn];
void dfs(int p,int fa){
mx[p]=mxx[p]=mxxx[p]=0;
siz[p]=1;
rep_e(i,p,u){
if(u==fa)continue;
dfs(u,p);
siz[p]=max(siz[p],siz[u]);
if(mx[u]+1>=mx[p]){
mxxx[p]=mxx[p];
mxx[p]=mx[p];
mx[p]=mx[u]+1;
}
else if(mx[u]+1>=mxx[p]){
mxxx[p]=mxx[p];
mxx[p]=mx[u]+1;
}
else if(mx[u]+1>mxxx[p]){
mxxx[p]=mx[u]+1;
}
}
siz[p]=max(siz[p],mx[p]);
if(mxx[p])siz[p]=max(siz[p],mx[p]+mxx[p]-1);
if(mx[p]==0)mx[p]=1;
}
void Dfs(int p,int fa,int up,int up2){ // all up , up link fa
if(p!=1)
update(1,1,n,1,up,siz[p]),
update(1,1,n,1,siz[p],up);
int mxsiz=0,mxxsiz=0;
rep_e(i,p,u){
if(u==fa)continue;
if(siz[u]>=mxsiz){
mxxsiz=mxsiz;
mxsiz=siz[u];
}
else if(siz[u]>mxxsiz){
mxxsiz=siz[u];
}
}
rep_e(i,p,u){
if(u==fa)continue;
int _up,_up2;
int son1=0,son2=0;
if(mx[u]+1==mx[p]){
son1=mxx[p],
son2=mxxx[p];
}
else if(mx[u]+1==mxx[p]){
son1=mx[p],
son2=mxxx[p];
}
else{
son1=mx[p],
son2=mxx[p];
}
if(!son1)
_up=max(max(up,up2+1),1),
_up2=max(1,up2+1);
else if(!son2)
_up=max(max(up,up2+son1),son1),
_up2=max(son1,up2+1);
else
_up=max(max(up,up2+son1),son1+son2-1),
_up2=max(son1,up2+1);
if(mxsiz==siz[u]){
if(mxxsiz){
_up=max(_up,mxxsiz);
}
}
else {
_up=max(_up,mxsiz);
}
Dfs(u,p,_up,_up2);
}
}
int main(){
int t=rd(),cas=0;
while(t--){
cas++;
mmm(tr,0);
mmm(laz,0);
init_edge();
n=rd();
rep(i,1,n-1){
int a=rd(),b=rd();
add(a,b);
add(b,a);
}
dfs(1,-1);
Dfs(1,-1,0,0);
LL sum=0;
rep(i,1,n-1){
sum+=1ll*query(1,1,n,i);
}
printf("%lld\n",sum);
}
return 0;
}