P2056 [ZJOI2007]捉迷藏(线段树维护直径)
P2056 [ZJOI2007]捉迷藏
根据直径的性质,当合并两个点集时,新直径的端点一定是被合并的两个点集直径四个端点中的某两个。 那么我们可以用线段树维护区间直径(的端点)。对于可用的点,初值设为自己;否则设为
求直径(两点间距离)需要求 lca。如果使用倍增/树剖,总复杂度就是
注意:这种做法是基于贪心思想的,所以不能处理负边权
#include<bits/stdc++.h>
#define mid (l+r)/2
#define ls ro<<1
#define rs ro<<1|1
using namespace std;
namespace FGF
{
int n,m;
const int N=3e5+5;
struct edg{
int to,nxt,w;
}e[N<<1];
int dep[N],dis[N],fa[N],lo[N],st[N<<1][25],dfn[N],num,id[N],cnt,head[N];
void add(int u,int v,int w)
{
cnt++;
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
e[cnt].w=w;
}
void dfs(int u,int f,int d)
{
dfn[u]=++num;id[num]=u;dep[num]=d;
for(int i=head[u];i;i=e[i].nxt)
if(e[i].to!=f)dis[e[i].to]=dis[u]+e[i].w,dfs(e[i].to,u,d+1),id[++num]=u,dep[num]=d;
}
void init()
{
lo[1]=0;
for(int i=2;i<=num;i++)lo[i]=lo[i>>1]+1;
for(int i=1;i<=num;i++)st[i][0]=i;
for(int j=1;j<=lo[num];j++)
for(int i=1;i<=num-(1<<j)+1;i++)
st[i][j]=(dep[st[i][j-1]]<=dep[st[i+(1<<(j-1))][j-1]]? st[i][j-1]:st[i+(1<<(j-1))][j-1]);
}
int getlca(int x,int y)
{
int l=dfn[x],r=dfn[y];
if(l>r)swap(l,r);
int k=lo[r-l+1];
return dep[st[l][k]]<=dep[st[r-(1<<k)+1][k]]? id[st[l][k]]:id[st[r-(1<<k)+1][k]];
}
int getdis(int x,int y)
{
return dis[x]+dis[y]-2*dis[getlca(x,y)];
}
struct tree{
int u,v;
}t[N<<4];
void pushup(int ro)
{
if(t[ls].u==-1&&t[ls].v==-1){t[ro]=t[rs];return;}
if(t[rs].u==-1&&t[rs].v==-1){t[ro]=t[ls];return;}
if(getdis(t[ls].u,t[ls].v)>getdis(t[rs].u,t[rs].v))t[ro]=t[ls];else t[ro]=t[rs];
if(getdis(t[ls].u,t[rs].u)>getdis(t[ro].u,t[ro].v))t[ro].u=t[ls].u,t[ro].v=t[rs].u;
if(getdis(t[ls].u,t[rs].v)>getdis(t[ro].u,t[ro].v))t[ro].u=t[ls].u,t[ro].v=t[rs].v;
if(getdis(t[ls].v,t[rs].u)>getdis(t[ro].u,t[ro].v))t[ro].u=t[ls].v,t[ro].v=t[rs].u;
if(getdis(t[ls].v,t[rs].v)>getdis(t[ro].u,t[ro].v))t[ro].u=t[ls].v,t[ro].v=t[rs].v;
}
void build(int ro,int l,int r)
{
if(l==r)
{
t[ro].u=t[ro].v=l;
return;
}
build(ls,l,mid),build(rs,mid+1,r);
pushup(ro);
}
void updat(int ro,int l,int r,int x)
{
if(l==r)
{
if(t[ro].u==-1&&t[ro].v==-1)t[ro].u=t[ro].v=x;
else t[ro].u=t[ro].v=-1;
return;
}
x<=mid? updat(ls,l,mid,x):updat(rs,mid+1,r,x);
pushup(ro);
}
void work()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int u,v,w=1;
scanf("%d%d",&u,&v);
add(u,v,w),add(v,u,w);
}
dfs(1,0,0);
init();
build(1,1,n);
scanf("%d",&m);
char s[5];int u;
while(m--)
{
scanf("%s",s);
if(s[0]=='C')scanf("%d",&u),updat(1,1,n,u);
else
{
if(t[1].u==-1||t[1].v==-1)puts("-1");
else printf("%d\n",getdis(t[1].u,t[1].v));
}
}
}
}
int main()
{
FGF::work();
return 0;
}