zoukankan      html  css  js  c++  java
  • luogu 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
    ",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
    ",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
    ",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
    ",L,R);
    		printf("%lld
    ",last=Query(x,L,R));
    	}
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    NOIP初赛知识点大全-普及+提高组
    cron表达式详解,cron表达式写法,cron表达式例子
    n2n的编译和运行、配置
    Visual Studio 2017 扩展
    iis url重写
    http重定向到https
    基于git命令的代码统计方法
    UseSwagger
    docker中mysql数据库的数据导入和导出
    Win10远程桌面提示你的凭据不工作的处理方法
  • 原文地址:https://www.cnblogs.com/With-penguin/p/12735034.html
Copyright © 2011-2022 走看看