CF1458F Range Diameter Sum

一、题目

点此看题

二、解法

考虑 \(f(l,r)\) 的实际意义就是保留 \([l,r]\) 中的点后树的直径。直径的合并是一个常见结论,但是还不足以解决这道题,这里我们要引入树上圆理论,可以去看看 cmd 的博客(我不想复读一遍)

考虑移动右端点,维护每个左端点对应的答案,虽然可能有单调性但并不好算出直径。其实这类涉及区间最值求和的问题可以考虑猫树分治,每次只处理过中点的 \(f(l,r)\),这时候我们移动左指针右指针就会有单调性:第一段是由左边决定的、第二段是共同决定的、第三段是由右边决定的\(...\)

我们把这个东西套上邻域理论,我们求出 \([l...mid]\) 的圆记为 \(A_l\),求出 \((mid...r]\) 的圆记为 \(B_r\)

  • 如果 \(A_l\) 包含 \(B_r\),那么答案就是 \(A_l\) 的直径。
  • 如果 \(B_r\) 包含 \(A_l\),那么答案就是 \(B_r\) 的直径。
  • 否则答案是 \(A_l\) 的半径 \(+\) \(B_r\) 的半径 \(+\) 两个圆的圆心距。

所以拿两个指针维护即可,最难算的是圆心距,可以拆成深度表达式,那么只需要计算 \(\tt lca\) 的深度和即可,发现这个就是套路的 LCA,写个 \(\tt bit\) 维护树剖即可,时间复杂度 \(O(n\log^3 n)\)

好难写啊,我调了一个晚上

#include <cstdio>
#include <cassert>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int M = 200005;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,Ind,siz[M],sd[M],sr[M],fa[M][20];
int ans,b1[M],b2[M],top[M],num[M],son[M],dep[M];
vector<int> g[M];
//tree dividing
void dfs1(int u,int p)
{
	dep[u]=dep[p]+1;
	siz[u]=1;fa[u][0]=p;
	for(int i=1;i<20;i++)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(auto v:g[u])
	{
		if(v==p) continue;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int tp)
{
	top[u]=tp;num[u]=++Ind;
	if(son[u]) dfs2(son[u],tp);
	for(auto v:g[u])
		if(v^fa[u][0] && v^son[u])
			dfs2(v,v);
}
//bit-array
int lowbit(int x)
{
	return x&(-x);
}
void upd(int x,int f)
{
	for(int i=x;i<=m;i+=lowbit(i))
		b1[i]+=f,b2[i]+=(x-1)*f;
}
int ask(int x)
{
	int r=0;
	for(int i=x;i>=1;i-=lowbit(i))
		r+=b1[i]*x,r-=b2[i];
	return r;
}
void ins(int u,int f)
{
	while(u)
	{
		upd(num[u]+1,-f);
		upd(num[top[u]],f);
		u=fa[top[u]][0];
	}
}
int qry(int u)
{
	int res=0;
	while(u)
	{
		res+=ask(num[u]);
		res-=ask(num[top[u]]-1);
		u=fa[top[u]][0];
	}
	return res;
}
//find lca and get dis
int lca(int u,int v)
{
	if(dep[u]<dep[v]) swap(u,v);
	for(int i=19;i>=0;i--)
		if(dep[fa[u][i]]>=dep[v])
			u=fa[u][i];
	if(u==v) return u;
	for(int i=19;i>=0;i--)
		if(fa[u][i]^fa[v][i])
			u=fa[u][i],v=fa[v][i];
	return fa[u][0];
}
int dis(int u,int v)
{
	return dep[u]+dep[v]-2*dep[lca(u,v)];
}
int jump(int u,int x)
{
	for(int i=19;i>=0;i--)
		if(x&(1<<i)) u=fa[u][i];
	return u;
}
//tree circle structure
struct node {int x,r;}s[M],q[M];
bool cmp(node a,node b)
{
	return a.r<b.r;
}
int get(int u,int v,int x)
{
	int p=lca(u,v);
	if(dep[u]-dep[p]>=x) return jump(u,x);
	return jump(v,dep[v]-dep[p]-(x-dep[u]+dep[p]));
}
node merge(node a,int b)
{
	int d=dis(a.x,b);
	if(a.r>=d) return a;//within
	return node{get(a.x,b,(d-a.r)/2),(d+a.r)/2};
}
int in(node a,node b)//does b contains a yes->1
{
	return a.r+dis(a.x,b.x)<=b.r;
}
void cdq(int l,int r)
{
	if(l==r) return ;
	int mid=(l+r)>>1;
	cdq(l,mid);cdq(mid+1,r);
	s[mid]=node{mid,0};sr[mid]=sd[mid]=0;
	s[mid+1]=node{mid+1,0};sr[mid+1]=0;
	//initialize for prefix & suffix
	for(int i=mid-1;i>=l;i--)
		s[i]=merge(s[i+1],i);
	for(int i=mid+2;i<=r;i++)
	{
		s[i]=merge(s[i-1],i);
		sr[i]=sr[i-1]+s[i].r;
	}
	for(int i=mid+1;i<=r;i++)
		sd[i]=sd[i-1]+dep[s[i].x];
	//cal l<=mid<=r
	int p1=mid,p2=mid,k=0;
	for(int i=mid;i>=l;i--)
	{//(mid,p1] left , (p1,p2] both , (p2,r] right
		while(p1<r && in(s[p1+1],s[i])) p1++;
		while(p2<r && !in(s[i],s[p2+1])) p2++;
		p2=max(p2,p1);
	//	assert(p1<=p2);
		ans+=2*(p1-mid)*s[i].r+2*(sr[r]-sr[p2])
			+(p2-p1)*dep[s[i].x]+(sd[p2]-sd[p1])
			+(p2-p1)*s[i].r+(sr[p2]-sr[p1]);
		if(p1<p2)
		{
			if(p1>mid) q[++k]=node{-s[i].x,p1};
			q[++k]=node{s[i].x,p2};
		}
	}
	sort(q+1,q+1+k,cmp);
	for(int i=mid+1,j=1;i<=r;i++)
	{
		ins(s[i].x,1);
		while(j<=k && q[j].r==i)
		{
			int x=q[j].x;
			if(x<0) ans+=2*qry(-x);
			else ans-=2*qry(x);
			j++;
		}
	}
	for(int i=mid+1;i<=r;i++) ins(s[i].x,-1);
}
signed main()
{
	n=read();m=2*n-1;
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		g[i+n].push_back(v);
		g[v].push_back(i+n);
		g[u].push_back(i+n);
		g[i+n].push_back(u);
	}
	dfs1(1,0);
	dfs2(1,1);
	cdq(1,n);
	printf("%lld\n",ans/2);
	//assert(ans%2==0);
}
posted @ 2021-10-25 22:14  C202044zxy  阅读(91)  评论(0编辑  收藏  举报