JZOJ6893. 【2020.11.25提高组模拟】小 T 与灵石(stone)题解

这道题需要转化,换根和卡常。
首先将集合中的点拉出来,找它们的直径
不需要什么虚树,随便挑一个集合里的点为根,做一遍dfs,找最远点x(要在集合里),以x为根重复以上操作,找到最远点y,x-y就是题解所谓“集合中点的直径”
然后, f [ i ] f[i] f[i]值可以转化成i与直径中点距离加上直径长度的一半
问题来了,如果有直径长度单数情况怎么办?
方法1(题解):发现这时中点在边上,如果中点在x-y边上,考虑新建点z,x,y分别与z连边,长度为1/2,此时z就是中点,为了避免小数,将所有边权*2
方法2(By FK)直径长度/2上取整,此时不必新建点,将x,y看成中点即可
我们在中点处(两个中点则两个中点都要)打上tag标记,代表直径长度/2上取整。
不可能nq复杂度更新f数组,考虑换根。
先从1开始dfs,那么有
a n s [ t ] = m i n ( m i n ( a n s [ s o n ] + 1 ) , t a g [ t ] ) ans[t]=min(min(ans[son]+1),tag[t]) ans[t]=min(min(ans[son]+1),tag[t])
然后换根,则有
a n s [ f [ k ] [ 1 ] ] = m i n ( a n s [ f [ k ] [ 1 ] , a n s [ t ] + 1 ) ans[f[k][1]]=min(ans[f[k][1],ans[t]+1) ans[f[k][1]]=min(ans[f[k][1],ans[t]+1)
本来需要消除儿子对根的影响,但是min并无所谓,sum就要
其实,理论上呢,这道题应该就结束了。
但是,这道题卡常加上OJ栈空间不够,让它十分恶心!
首先,你会发现自己RE78(如果不WA)
原因:OJ栈空间不够
解决方案:人工栈
然后就是各种各样的TLE
两点间距离可以用ST表预处理,虽然预处理是log的,但查询是O(1)的
此时,如果你还TLE,卡常吧
方法包括但不限于register,inline,if语句改三元运算符等
然后,运气好的话,你就可以AC了
或者依靠OJ的随机摆动,找到快的评测机AC
例如某HZH大佬交了4次摆动一下就切了
正负400ms都是常事,不要惊讶。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define mem(x) memset(x,0,sizeof(x))
#define min(a,b) a<b?a:b 
#define R register
#define I inline
using namespace std;
int xl[600005],z[300005],tag[300005],ans[300005],a[300005],dep[300005],b[300005][20],mi[20],f[300005][3],q[300005];
int st[600005][20],lc[600005][20],lg[600005],type[300005],zt[300005],zson[300005],zk[300005],mn[300005],in[300005],out[300005];
int i,j,k,m,n,o,p,l,s,t,times,g,h,top,tot;
I char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
I void read(int &x){
    char ch=nc();x=0;
    while (!(ch>='0'&&ch<='9')) ch=nc();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=nc();
}
I void insert(R int x,R int y) {f[++t][1]=y,f[t][2]=q[x],q[x]=t;}
int ST(int x,int y)
{
	R int k=lg[y-x+1];
	return st[x][k]<st[y-(1<<k)+1][k]?lc[x][k]:lc[y-(1<<k)+1][k];
}
int getlca(int x,int y)
{
	if (in[x]<=in[y]&&out[y]<=out[x]) return x;
	if (in[y]<=in[x]&&out[x]<=out[y]) return y;
	return in[x]<=out[y]?ST(in[x],out[y]):ST(in[y],out[x]);
}
I int getdis(R int x,R int y) {R int lca=getlca(x,y);return dep[x]+dep[y]-2*dep[lca];}
I int jump(R int x,R int y,R int lca,R int g)
{
	if (dep[x]-dep[lca]>=g)
	{
		for (R int i=18;i>=0;i--)
			(g>=mi[i])?g-=mi[i],x=b[x][i]:g=g;
		return x; 
	} else {
		g-=(dep[x]-dep[lca]);x=y;
		g=dep[y]-dep[lca]-g;
		for (R int i=18;i>=0;i--)
			(g>=mi[i])?g-=mi[i],x=b[x][i]:g=g;
		return x; 
	}
}
I int find(R int x)
{
	R int s=-1,pos=0;
	for (R int i=1;i<=m;i++)
	{
		R int o=getdis(a[i],x);
		(o>s)?s=o,pos=i:o=o;
	}
	return pos;
}
I void dg(R int t)
{
	type[++top]=0,zt[top]=t;
	while (top)
	{
		wyd:;
		R int t=zt[top],son=zson[top],k=zk[top];
		if (type[top]==1) goto WYD;
		for (k=q[t];k;k=f[k][2])
		{
			son=f[k][1];
			ans[f[k][1]]=min(ans[f[k][1]],ans[t]+1),
			zt[top]=t,zson[top]=son,zk[top]=k,type[top]=1;
			type[++top]=0,zt[top]=son;
			goto wyd;
			WYD:;
			mn[t]=min(mn[t],ans[f[k][1]]+1);
		}
		ans[t]=min(mn[t],tag[t]);
		top--;
	}
}
I void dfs(R int t)
{
	type[++top]=0,zt[top]=t;
	while (top)
	{
		wyd:;
		R int t=zt[top],son=zson[top],k=zk[top];
		if (type[top]==1) goto WYD;
		for (k=q[t];k;k=f[k][2])
		{
			son=f[k][1];
			ans[f[k][1]]=min(ans[f[k][1]],ans[t]+1),
			zt[top]=t,zson[top]=son,zk[top]=k,type[top]=1;
			type[++top]=0,zt[top]=son;
			goto wyd;
			WYD:;
		}
		top--;
	}
}
I void pre(R int t)
{
	type[++top]=0,zt[top]=t;
	while (top)
	{
		wyd:;
		R int t=zt[top],son=zson[top],k=zk[top];
		if (type[top]==1) goto WYD;
		tot++;in[t]=tot<in[t]?tot:in[t],out[t]=(tot>out[t])?tot:out[t],xl[tot]=t;
		for (k=q[t];k;k=f[k][2])
		{
			son=f[k][1];
			dep[son]=dep[t]+1;
			zt[top]=t,zson[top]=son,zk[top]=k,type[top]=1;
			type[++top]=0,zt[top]=son;
			goto wyd;
			WYD:;
			tot++;in[t]=tot<in[t]?tot:in[t],out[t]=(tot>out[t])?tot:out[t],xl[tot]=t;
		}
		top--;
	}
}
void prepare(){
	lg[0]=-1;
	for (R int i=1;i<=tot;i++) lg[i]=lg[i>>1]+1;
	for (R int i=1;i<=19;i++)
		for (R int j=1;j+(1<<i)-1<=tot;j++)
		{
			int opt=st[j][i-1]<st[j+(1<<(i-1))][i-1];
			lc[j][i]=(opt>0)?lc[j][i-1]:lc[j+(1<<(i-1))][i-1];
			st[j][i]=(opt>0)?st[j][i-1]:st[j+(1<<(i-1))][i-1];
		}
}
signed main()
{
	freopen("stone.in","r",stdin);
	freopen("stone.out","w",stdout);
	read(n);dep[1]=1;
	for (R int i=mi[0]=1;i<=19;i++) mi[i]=mi[i-1]*2;
	for (R int i=2;i<=n;i++) read(o),insert(o,i),b[i][0]=o;
	for (R int i=1;i<=18;i++)
		for (R int j=1;j<=n;j++)
			b[j][i]=b[b[j][i-1]][i-1];
	memset(in,60,sizeof(in));
	pre(1);
	for (i=1;i<=tot;i++) 
		st[i][0]=dep[xl[i]],lc[i][0]=xl[i];
	prepare();
	read(times);memset(tag,60,sizeof(tag));
	while (times--)
	{
		read(m);
		for (R int i=1;i<=m;i++) read(a[i]);
		g=find(a[1]),h=find(a[g]);
		g=a[g],h=a[h];
		int dis=getdis(g,h),lca=getlca(g,h);
		if (!(dis&1))
		{
			R int ad=dis>>1,mid=jump(g,h,lca,ad);
			tag[mid]=min(tag[mid],ad);
		} else {
			R int ad=dis>>1,
			mid1=jump(g,h,lca,ad),
			mid2=jump(h,g,lca,ad);
			tag[mid1]=min(tag[mid1],ad+1),tag[mid2]=min(tag[mid2],ad+1);
		}
	}
	memset(ans,60,sizeof(ans)),memset(mn,60,sizeof(mn));
	mem(zt),mem(zson),mem(type),mem(zk);top=0;
	dg(1);
	mem(zt),mem(zson),mem(type),mem(zk);top=0;
	dfs(1);
	for (R int i=1;i<=n;i++) printf("%d\n",ans[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值