P3241 [HNOI2015]开店

时间:2020-04-20
本文章向大家介绍P3241 [HNOI2015]开店,主要包括P3241 [HNOI2015]开店使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

这里是一种动态点分治的解法(不过听说树剖+主席树更快?)。

首先先考虑除去年龄的限制这道题怎么做。也就是给你一棵树,每次询问一个点到所有其他点的距离和。

由于路径问题不太关系树的形态,并且问的又是一个点和整棵树之间的关系,所以可以考虑动态点分治:

  • 每个点保存它在点分树内的子树的信息
  • \(dis1[i]\)表示\(i\)子树内所有点到它的距离之和,\(dis2[i]\)表示\(i\)子树内所有点到\(fa[i]\)(依然是点分树上的父亲)的距离
  • 查询就直接跳点分树好了

现在带上年龄的限制,我们依然可以“每个点保存它在点分树内的子树的信息”,我们可以用一个\(vector\)把一棵子树里的点全部保存下来,按年龄拍个序,求一下\(dis1\)\(dis2\)的后(前)缀和,最后询问的时候二分一下就好了。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;

typedef long long LL;
const int N=500009,INF=1<<30;
int n,Q,age[N],log[N],A,head[N],cnt,F[N],root,R[N],L[N],Index,DFN[N],rev[N];
struct D
{
	LL dis1,dis2;
	int age;
	bool operator < (const D &A)const
	{
		return age<A.age;
	}
};
vector <D> b[N];
struct Edge
{
	int nxt,to;
}g[N*2];
struct G
{
	int head[N],cnt,Euler[N],Index,Fst[N],f[N][30],dep[N],siz[N],del[N];
	LL dis[N];
	struct Edge
	{
		int nxt,to,w;
	}g[N*2];
	
	void add(int from,int to,int w)
	{
		g[++cnt].nxt=head[from];
		g[cnt].to=to;
		g[cnt].w=w;
		head[from]=cnt;
	}
	void dfs(int x,int fa)
	{
		Euler[++Index]=x,f[Index][0]=x,Fst[x]=Index;
		for (int i=head[x];i;i=g[i].nxt)
		{
			int v=g[i].to;
			if(v==fa)
				continue;
			dep[v]=dep[x]+1,dis[v]=dis[x]+g[i].w;
			dfs(v,x);
			Euler[++Index]=x,f[Index][0]=x;
		}
	}
	int LCA(int x,int y)
	{
		if(Fst[x]>Fst[y])
			swap(x,y);
		x=Fst[x],y=Fst[y];
		int k=log[y-x+1];
		return dep[f[x][k]]<dep[f[y-(1<<k)+1][k]]?f[x][k]:f[y-(1<<k)+1][k];
	}
	LL Get_Dis(int x,int y)
	{
		return dis[x]+dis[y]-2*dis[LCA(x,y)];
	}
	void DFS(int x,int fa)
	{
		siz[x]=1;
		for (int i=head[x];i;i=g[i].nxt)
		{
			int v=g[i].to;
			if(v==fa||del[v])
				continue;
			DFS(v,x);
			siz[x]+=siz[v];
		}
	}
	int Get_Weight(int x)
	{
		DFS(x,-1);
		int k=siz[x]/2,fa=-1;
		while(1)
		{
			int tmp=0;
			for (int i=head[x];i;i=g[i].nxt)
			{
				int v=g[i].to;
				if(v==fa||del[v])
					continue;
				if(siz[tmp]<siz[v])
					tmp=v;
			}
			if(siz[tmp]<=k)
				return x;
			fa=x,x=tmp;
		}
	}
	void work()
	{
		dfs(1,-1);
		for (int j=1;1<<j<=Index;j++)
			for (int i=1;i+(1<<j)<=Index;i++)
				if(dep[f[i][j-1]]<dep[f[i+(1<<j-1)][j-1]])
					f[i][j]=f[i][j-1];
				else
					f[i][j]=f[i+(1<<j-1)][j-1];
	}
}T;

void add(int from,int to)
{
	g[++cnt].nxt=head[from];
	g[cnt].to=to;
	head[from]=cnt;
}

void init()
{
	log[0]=-1;
	for (int i=1;i<=N-9;i++)
		log[i]=log[i>>1]+1;
	scanf("%d %d %d",&n,&Q,&A);
	for (int i=1;i<=n;i++)
		scanf("%d",&age[i]);
	for (int i=1;i<n;i++)
	{
		int x,y,z;
		scanf("%d %d %d",&x,&y,&z);
		T.add(x,y,z),T.add(y,x,z);
	}
	T.work();
}

void build(int fa)
{
	T.del[fa]=1,DFN[fa]=++Index,L[fa]=Index,rev[Index]=fa;
	for (int i=T.head[fa];i;i=T.g[i].nxt)
	{
		int v=T.g[i].to;
		if(v==fa||T.del[v])
			continue;
		int w=T.Get_Weight(v);
		F[w]=fa,add(fa,w),add(w,fa);
		build(w);
	}
	R[fa]=Index;
	//printf("%d %d %d\n",fa,L[fa],R[fa]);
}

void print(int x,int fa)
{
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa)
			continue;
		printf("%d %d\n",x,v);
		print(v,x);
	}
}

void dfs(int x,int fa)
{
	b[x].push_back((D){0,fa!=-1?T.Get_Dis(fa,x):0,age[x]});
	b[x].push_back((D){0,0,INF});
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa)
			continue;
		for (int j=L[v];j<=R[v];j++)
		{
			int J=rev[j];
			b[x].push_back( ( D ) { T.Get_Dis(x,J) , fa!=-1?T.Get_Dis(fa,J):0 , age[J] } );
		}
		dfs(v,x);
	}
	sort(b[x].begin(),b[x].end());
	for (int i=b[x].size()-2;i>=0;i--)
		b[x][i].dis1+=b[x][i+1].dis1,b[x][i].dis2+=b[x][i+1].dis2;
	//printf("now_%d\n",x);
	//for (int i=0;i<b[x].size();i++)
		//printf("%d ",b[x][i].age);puts("");
}

LL Query(int x,int l,int r)
{
	vector <D> ::iterator L,R;
	LL ans=0;
	for (int i=x;i;i=F[i])
	{
		L=lower_bound(b[i].begin(),b[i].end(),(D){0,0,l});
		R=upper_bound(b[i].begin(),b[i].end(),(D){0,0,r});
		ans+=(L->dis1-R->dis1)+1LL*(R-L)*T.Get_Dis(x,i);
		if(F[i])
			ans-=1LL*(R-L)*T.Get_Dis(x,F[i])+L->dis2-R->dis2;
	}
	return ans;
}

void work()
{
	root=T.Get_Weight(1);
	//puts("pipi");
	build(root);
	//puts("houhou");
	//print(root,-1);
	dfs(root,-1);
	LL last=0;
	for (int _=1;_<=Q;_++)
	{
		int x,y,z;
		scanf("%d %d %d",&x,&y,&z);
		int L=min((y+last)%A,(z+last)%A),R=max((y+last)%A,(z+last)%A);
		if(L>R)
			swap(L,R);
		//printf("L=%d R=%d\n",L,R);
		printf("%lld\n",last=Query(x,L,R));
	}
}

int main()
{
	init();
	work();
	return 0;
}

原文地址:https://www.cnblogs.com/With-penguin/p/12735034.html