hdu 4812 D Tree

题意:有一棵树,树中所有结点有一个权值,求出字典序最小的点对,满足这两个点间的简单路径中所有结点的权值积等于k

做法:树分治,所有经过x点满足要求的路径点对去更新ans,枚举x即可。

由于这里所有的权值小于mod,所以不用考虑0的情况,方便许多。

用map乱搞会超时,还是老老实实用数组模拟hash。

#include<map>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<climits>
#include<list>
#include<iomanip>
#include<stack>
#include<set>
using namespace std;
typedef long long ll;
const ll mod=1000003;
ll k;
int tail;
int head[100010];
struct Edge
{
	int to,next;
}edge[200010];
int mid,tree_size;
bool vis[100010];
int sb_size[100010],mx_size[100010];
void seek_mid(int fa,int from)
{
	sb_size[from]=1;
	mx_size[from]=0;
	for(int i=head[from];i!=-1;i=edge[i].next)
	{
		int to=edge[i].to;
		if(!vis[to]&&to!=fa)
		{
			seek_mid(from,to);
			sb_size[from]+=sb_size[to];
			mx_size[from]=max(mx_size[from],sb_size[from]);
		}
	}
	mx_size[from]=max(mx_size[from],tree_size-sb_size[from]);
	if(mx_size[mid]>mx_size[from])
		mid=from;
}
int path_size[2];
int path[2][100010],index[2][mod];
ll w[100010];
void cnt(int fa,int from,ll val)
{
	if(index[0][val]==0||index[0][val]>from)
	{
		if(index[0][val]==0)
			path[0][path_size[0]++]=val;
		index[0][val]=from;
	}
	sb_size[from]=1;
	for(int i=head[from];i!=-1;i=edge[i].next)
	{
		int to=edge[i].to;
		if(!vis[to]&&fa!=to)
		{
			cnt(from,to,val*w[to]%mod);
			sb_size[from]+=sb_size[to];
		}
	}
}
int ansl,ansr;
void update(int l,int r)
{
	if(l>r)
		swap(l,r);
	if(l<ansl)
	{
		ansl=l;
		ansr=r;
	}
	else if(l==ansl&&r<ansr)
		ansr=r;
}
ll fac[mod];
void cnt()
{
	for(int i=head[mid];i!=-1;i=edge[i].next)
	{
		int to=edge[i].to;
		if(!vis[to])
		{
			path_size[0]=0;
			cnt(mid,to,w[to]);
			for(int j=0;j<path_size[0];j++)
			{
				if(path[0][j]*w[mid]%mod==k)
					update(mid,index[0][path[0][j]]);
				int t=k*fac[path[0][j]*w[mid]%mod]%mod;
				if(index[1][t]!=0)
					update(index[0][path[0][j]],index[1][t]);
			}
			for(int j=0;j<path_size[0];j++)
			{
				if(index[1][path[0][j]]==0||
				index[1][path[0][j]]>index[0][path[0][j]])
				{
					if(index[1][path[0][j]]==0)
						path[1][path_size[1]++]=path[0][j];
					index[1][path[0][j]]=index[0][path[0][j]];
				}
				index[0][path[0][j]]=0;
			}
		}
	}
}
void dfs()
{
	vis[mid]=1;
	path_size[1]=0;
	cnt();
	for(int i=0;i<path_size[1];i++)
		index[1][path[1][i]]=0;
	for(int i=head[mid];i!=-1;i=edge[i].next)
	{
		int to=edge[i].to;
		if(!vis[to])
		{
			mx_size[mid=0]=100010;
			tree_size=sb_size[to];
			seek_mid(0,to);
			dfs();
		}
	}
}
ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)
			ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}
void create()
{
	for(int i=1;i<mod;i++)
		fac[i]=qpow(i,mod-2);
}
void add(int from,int to)
{
	edge[tail].to=to;
	edge[tail].next=head[from];
	head[from]=tail++;
}
int main()
{
	create();
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		memset(vis,0,sizeof(vis));
		int t;
		scanf("%d",&t);
		k=t;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&t);
			w[i]=t;
		}
		tail=0;
		memset(head,-1,sizeof(head));
		for(int i=1;i<n;i++)
		{
			int from,to;
			scanf("%d%d",&from,&to);
			add(from,to);
			add(to,from);
		}
		tree_size=n;
		ansl=mx_size[mid=0]=100010;
		seek_mid(0,1);
		dfs();
		if(ansl==100010)
			puts("No solution");
		else
			printf("%d %d\n",ansl,ansr);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值