HDU 4812 D Tree (树上点分治)
2015-07-11 11:14
483 查看
题目地址:HDU 4812
这题是13年南京区域赛的现场题。
树分治思想。
树分治的过程中记录下每个子树的所有到达根的路径的积,用best记录下每个积的最小端点,然后再枚举当前子树的每个积,然后用逆元的方法求出当积为k时所需要的另一个端点值,并更新答案。
代码如下:
这题是13年南京区域赛的现场题。
树分治思想。
树分治的过程中记录下每个子树的所有到达根的路径的积,用best记录下每个积的最小端点,然后再枚举当前子树的每个积,然后用逆元的方法求出当积为k时所需要的另一个端点值,并更新答案。
代码如下:
#include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <stdio.h> #include <time.h> using namespace std; #define LL __int64 #define pi acos(-1.0) #pragma comment(linker, "/STACK:1024000000") const int mod=1e6+3; const int INF=0x3f3f3f3f; const double eqs=1e-9; const int MAXN=100000+10; int head[MAXN], cnt, root, min1, ans1, ans2, tot, k, ff; int siz[MAXN], vis[MAXN], best[MAXN*10], flag[MAXN*10]; LL Inv[MAXN*10], a[MAXN]; struct N { LL x; int num; }F[MAXN]; struct node { int v, next; }edge[MAXN<<1]; void add(int u, int v) { edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; } void getroot(int u, int fa, int s) { int max1=0; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==fa||vis[v]) continue ; getroot(v,u,s); max1=max(max1,siz[v]); } max1=max(max1,s-siz[u]); if(min1>max1){ min1=max1; root=u; } } void getsize(int u, int fa) { siz[u]=1; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==fa||vis[v]) continue ; getsize(v,u); siz[u]+=siz[v]; } } LL ksm(LL x) { LL ans=1; int k=mod-2; while(k){ if(k&1) ans=ans*x%mod; k>>=1; x=x*x%mod; } return ans; } void getF(int u, int fa, LL val) { F[tot].x=val; F[tot++].num=u; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==fa||vis[v]) continue ; getF(v,u,val*a[v]%mod); } } void work(int u) { vis[u]=1; int i, j; LL tmp; for(i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(vis[v]) continue ; min1=INF; getsize(v,u); getroot(v,u,siz[v]); work(root); } ff++; best[1]=u; flag[1]=ff; for(i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(vis[v]) continue; tot=0; getF(v,u,a[v]); for(j=0;j<tot;j++){ tmp=(LL)k*Inv[F[j].x*a[u]%mod]%mod; if(flag[tmp]!=ff) continue ; int minnum=min(best[tmp],F[j].num); int maxnum=max(best[tmp],F[j].num); if(ans1>minnum){ ans1=minnum; ans2=maxnum; } else if(ans1==minnum&&ans2>maxnum) ans2=maxnum; } for(j=0;j<tot;j++){ if(flag[F[j].x]!=ff||best[F[j].x]>F[j].num){ best[F[j].x]=F[j].num; flag[F[j].x]=ff; } } } vis[u]=0; } void init() { memset(head,-1,sizeof(head)); cnt=0; memset(vis,0,sizeof(vis)); ans1=ans2=INF; memset(flag,-1,sizeof(flag)); } void init1() { Inv[0]=0; for(int i=1;i<mod;i++){ Inv[i]=ksm((LL)i); } } int main() { int n, i, u, v; init1(); while(scanf("%d%d",&n,&k)!=EOF){ init(); ff=0; for(i=1;i<=n;i++){ scanf("%I64d",&a[i]); } for(i=1;i<n;i++){ scanf("%d%d",&u,&v); add(u,v); add(v,u); } min1=INF; getsize(1,-1); getroot(1,-1,n); work(root); if(ans1==INF) puts("No solution"); else printf("%d %d\n",ans1,ans2); } return 0; }