【JZOJ4225】宝藏

description


analysis

  • 倍增+++期望

  • 题解鲜有地写的很清晰……

  • 大概就这样了吧……

  • 然后对于求出来的fff值什么的,用倍增维护

  • 每次询问其实就是用倍增在树上跳来跳去,这个实现很简单


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define MAXP 505
#define MAXN 50005
#define MAXM MAXN*2
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define rep(i,a) for (reg i=last[a];i;i=next[i])
#define O3 __attribute__((optimize("-O3")))

using namespace std;

ll anc[MAXN][17],dis1[MAXN][17],dis2[MAXN][17];
ll last[MAXM],next[MAXM],tov[MAXM];
ll f1[MAXN],f2[MAXN],d[MAXN],depth[MAXN],v[MAXP];
ll n,p,q,ans,tot,test;

O3 inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
O3 inline ll max(ll x,ll y)
{
	return x>y?x:y;
}
O3 inline void link(ll x,ll y)
{
	next[++tot]=last[x],last[x]=tot,tov[tot]=y;
}
O3 inline void dfs1(ll x,ll y)
{	
	rep(i,x)if (tov[i]!=y)
	{
		anc[tov[i]][0]=x;
		depth[tov[i]]=depth[x]+1;
	}
	f1[x]=d[x];
	rep(i,x)if (tov[i]!=y)f1[x]+=f1[tov[i]];
	f2[x]=max(0,2*(n-1)-f1[x]);
}
O3 inline void dfs2(ll x,ll y)
{
	rep(i,x)if (tov[i]!=y)
	{
		dis1[tov[i]][0]=f1[tov[i]];
		dis2[tov[i]][0]=f2[tov[i]];
		dfs2(tov[i],x);
	}
}
O3 inline ll lca(ll x,ll y)
{
	if (depth[x]<depth[y])swap(x,y);
	fd(i,16,0)if (depth[anc[x][i]]>depth[y])x=anc[x][i];
	if (depth[x]!=depth[y])x=anc[x][0];
	fd(i,16,0)if (anc[x][i]!=anc[y][i])x=anc[x][i],y=anc[y][i];
	return x==y?x:anc[x][0];
}
O3 int main()
{
	//freopen("T3.in","r",stdin);
	test=read();
	while (test--)
	{
		tot=0;
		memset(d,0,sizeof(d));
		memset(f1,0,sizeof(f1));
		memset(f2,0,sizeof(f2));
		memset(last,0,sizeof(last));
		memset(next,0,sizeof(next));
		memset(tov,0,sizeof(tov));
		memset(anc,0,sizeof(anc));
		memset(dis1,0,sizeof(dis1));
		memset(dis2,0,sizeof(dis2));
		n=read();
		fo(i,1,n-1)
		{
			ll x=read()+1,y=read()+1;
			link(x,y),link(y,x),++d[x],++d[y];
		}
		depth[1]=1,dfs1(1,0),dfs2(1,0);
		fo(j,1,floor(log2(n)))fo(i,1,n)
		{
			anc[i][j]=anc[anc[i][j-1]][j-1];
			dis1[i][j]=dis1[i][j-1]+dis1[anc[i][j-1]][j-1];
			dis2[i][j]=dis2[i][j-1]+dis2[anc[i][j-1]][j-1];
		}
		q=read();
		while (q--)
		{
			p=read(),ans=0;
			fo(i,0,p)v[i]=read()+1;
			fo(i,1,p)
			{
				ll x=v[i-1],y=v[i],LCA=lca(x,y);
				if (LCA!=x)fd(i,16,0)if (depth[anc[x][i]]>=depth[LCA])ans+=dis1[x][i],x=anc[x][i];
				if (LCA!=y)fd(i,16,0)if (depth[anc[y][i]]>=depth[LCA])ans+=dis2[y][i],y=anc[y][i];
			}
			printf("%lld.0000\n",ans);
		}
		printf("\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值