P3241 [HNOI2015] Opening a store

Here is a dynamic point divide and conquer solution (but I heard that tree section + chairman tree is faster?).

First consider how to remove the age restriction. That is to give you a tree, each time asking the distance between one point and all other points.

Since the path problem is not very related to the shape of the tree, and the relationship between a point and the entire tree is also asked, it is possible to consider dynamic point divide and conquer:

  • Each point saves the information of its subtree in the point division tree
  • Let \ (dis1 [i] \) denote the sum of the distances from all points in the \ (i \) subtree to it, \ (dis2 [i] \) denote all points in the \ ( i \) subtree to \ (fa [i] \) (still the father of the point tree)
  • Query and jump directly to the point tree

Now with the age limit, we can still "save the information of each subtree in the point tree of each point", we can use a \ (vector \) to save all the points in a subtree, according to age Take a sequence and find the suffixes of the back (front) of \ (dis1 \) and \ (dis2 \) , and it will be fine when you finally ask.

Code:

#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;
}

Guess you like

Origin www.cnblogs.com/With-penguin/p/12735034.html