关于动态维护树中点集直径的研究
注:下文讲到的所有方法均依赖于树的边权为正数。
例题:P2056。
这是括号序动态维护的方法,这里不讲。
注意到一个结论:设 为两个树中的点集。
记 为一个大小为 集合,其中两个点分别为 集合中直径的两个端点(多个取任意)。
则有结论:,满足 是 集合中直径的两个端点。请读者不难自证。
那么,根据这个结论,我们考虑利用线段树来维护区间直径。合并区间时直接暴力合并计算即可。
现在如果要单 维护的话需要 求两点的 ,即需要 求 。
的六种求法,不会的这里学习,我推荐 序来求。
#include<bits/stdc++.h>
#define P pair<int,int>
#define fi first
#define se second
#define LL long long
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
using namespace std;
const int N=1e5+5;
int n,m,tot,head[N],d[N],id[N],_id[N],mn[N][25],cnt;
bool a[N];P b[N<<2];
struct edge{int to,nex;}e[N<<1];
inline void add(int u,int v)
{
e[++tot]={v,head[u]};head[u]=tot;
e[++tot]={u,head[v]};head[v]=tot;
}
inline int MN(int x,int y){return d[x]<d[y]?x:y;}
void dfs(int x,int fa)
{
d[x]=d[mn[id[x]=++tot][0]=fa]+1;_id[tot]=x;
for(int i=head[x];i;i=e[i].nex){int to=e[i].to;if(to!=fa) dfs(to,x);}
}
inline int lca(int u,int v)
{
if(u==v) return u;u=id[u],v=id[v];u>v&&(swap(u,v),1);
int t=__lg(v-(u++));return MN(mn[u][t],mn[v-(1<<t)+1][t]);
}
inline int dis(int u,int v){return (u==-1||v==-1)?-1:d[u]+d[v]-(d[lca(u,v)]<<1);}
inline P hb(P x,P y)
{
int a=dis(x.fi,y.fi),b=dis(x.fi,y.se),c=dis(x.se,y.fi),d=dis(x.se,y.se),e=dis(x.fi,x.se),f=dis(y.fi,y.se),g=max({a,b,c,d,e,f});
if(e==g) return x;if(f==g) return y;
return {(a==g||b==g)?x.fi:x.se,(a==g||c==g)?y.fi:y.se};
}
void build(int l,int r,int wz)
{
if(l==r) return b[wz]={l,l},void();int mid=(l+r)>>1;
build(l,mid,wz<<1);build(mid+1,r,wz<<1|1);b[wz]=hb(b[wz<<1],b[wz<<1|1]);
}
void updata(int l,int r,int wz,int x)
{
if(l==r) return b[wz]=a[x]?(P){x,x}:(P){-1,-1},void();
int mid=(l+r)>>1;
if(x<=mid) updata(l,mid,wz<<1,x);else updata(mid+1,r,wz<<1|1,x);
b[wz]=hb(b[wz<<1],b[wz<<1|1]);
}
int main()
{
scanf("%d",&n);int u,v,x;char c[1];
for(int i=1;i<n;i++) scanf("%d%d",&u,&v),add(u,v);scanf("%d",&m);
for(int i=1;i<=n;i++) a[i]=1;cnt=n;tot=0;dfs(1,0);
for(int i=1;i<=__lg(n);i++) for(int j=1;j+(1<<(i-1))<=n;j++) mn[j][i]=MN(mn[j][i-1],mn[j+(1<<(i-1))][i-1]);
build(1,n,1);
while(m--)
{
scanf("%s",c);
if(c[0]=='C') scanf("%d",&x),a[x]^=1,a[x]?cnt++:cnt--,updata(1,n,1,x);
else
{
if(!cnt){puts("-1");continue;}
if(cnt==1){puts("0");continue;}
u=b[1].fi,v=b[1].se;x=dis(u,v);printf("%d\n",x);
}
}
return 0;
}
练习 :CF1413,基本就是板子加一点小技巧。大家最好不要用我这种写法维护这个事情(建议用括号序,参考题解),否则会超时。
强行卡过的
#include<bits/stdc++.h>
#define P pair<int,int>
#define fi first
#define se second
#define LL long long
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
using namespace std;
namespace IO
{
const int _Pu=2e7+5,_d=32;
char buf[_Pu],obuf[_Pu],*p1=buf+_Pu,*p2=buf+_Pu,*p3=obuf,*p4=obuf+_Pu-_d;
inline void fin()
{
memmove(buf,p1,p2-p1);
int rlen=fread(buf+(p2-p1),1,p1-buf,stdin);
if(p1-rlen>buf) buf[p2-p1+rlen]=EOF;p1=buf;
}
inline void fout(){fwrite(obuf,p3-obuf,1,stdout),p3=obuf;}
inline int rd()
{
if(p1+_d>p2) fin();int isne=0,x=0;
for(;!isdigit(*p1);++p1) isne=(*p1=='-');x=(*p1++-'0');
for(;isdigit(*p1);++p1) x=x*10+(*p1-'0');
if(isne) x=-x;return x;
}
inline void wr(int x,char end='\n')
{
if(!x) return *p3++='0',*p3++=end,void();
if(x<0) *p3++='-',x=-x;
char sta[20],*top=sta;
do{*top++=(x%10)+'0';x/=10;}while(x);
do{*p3++=*--top;}while(top!=sta);(*p3++)=end;
}
}
const int N=5e5+5;
int n,m,tot,head[N],d[N],id[N],_id[N],siz[N],mn[25][N],o,rt0,rt1,ls[N<<3],rs[N<<3],L,R;
bool a[N];P b[N<<3],E[N];
struct edge{int to,nex,w;}e[N<<1];
inline void add(int u,int v,int w)
{
e[++tot]={v,head[u],w};head[u]=tot;
e[++tot]={u,head[v],w};head[v]=tot;
}
#define MN(x,y) d[x]<d[y]?x:y
inline void dfs(int x,int fa)
{
d[x]=d[mn[0][id[x]=++tot]=fa]+1;_id[tot]=x;siz[x]=1;
for(int i=head[x];i;i=e[i].nex){int to=e[i].to;if(to^fa) a[to]=a[x]^e[i].w,dfs(to,x),siz[x]+=siz[to];}
}
inline int lca(int u,int v)
{
if(u==v) return u;u=id[u],v=id[v];u>v&&(swap(u,v),1);
int t=__lg(v-(u++));return MN(mn[t][u],mn[t][v-(1<<t)+1]);
}
#define dis(u,v) ::d[u]+::d[v]-(::d[lca(u,v)]<<1)
inline void pushup(int wz)
{
P x=b[ls[wz]],y=b[rs[wz]];
if(x.fi==-1) return b[wz]=y,void();if(y.fi==-1) return b[wz]=x,void();
int a=dis(x.fi,y.fi),b=dis(x.fi,y.se),c=dis(x.se,y.fi),d=dis(x.se,y.se),e=dis(x.fi,x.se),f=dis(y.fi,y.se),g=max({a,b,c,d,e,f});
if(e==g) return ::b[wz]=x,void();if(f==g) return ::b[wz]=y,void();
::b[wz]={(a==g||b==g)?x.fi:x.se,(a==g||c==g)?y.fi:y.se};
}
inline void build(int l,int r,int &wz)
{
wz=++tot;int mid=(l+r)>>1;
if(l==r) return b[wz]=(a[_id[l]]^o)?(P){-1,-1}:(P){_id[l],_id[l]},void();
build(l,mid,ls[wz]);build(mid+1,r,rs[wz]);pushup(wz);
}
inline void updata(int l,int r,int &wz,int &wz1)
{
if(L<=l&&r<=R) return swap(wz,wz1);
int mid=(l+r)>>1;
if(L<=mid) updata(l,mid,ls[wz],ls[wz1]);
if(mid<R) updata(mid+1,r,rs[wz],rs[wz1]);
pushup(wz);pushup(wz1);
}
int main()
{
n=IO::rd();int u,v,x;
for(int i=1;i<n;i++) u=IO::rd(),v=IO::rd(),x=IO::rd(),add(u,v,x),E[i]={u,v};m=IO::rd();tot=0;dfs(1,0);
for(int i=1;i<=__lg(n);i++) for(int j=1;j+(1<<(i-1))<=n;j++) mn[i][j]=MN(mn[i-1][j],mn[i-1][j+(1<<(i-1))]);
tot=0;build(1,n,rt0);o=1;build(1,n,rt1);
while(m--)
{
x=IO::rd();int t=d[E[x].fi]>d[E[x].se]?E[x].fi:E[x].se;L=id[t],R=id[t]+siz[t]-1;
updata(1,n,rt0,rt1);IO::wr(max(dis(b[rt0].fi,b[rt0].se),dis(b[rt1].fi,b[rt1].se)));
}
return IO::fout(),0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】