题目链接:https://vjudge.net/problem/HDU-4812
题意:给定一颗带点权的树,求是否存在一条路经的上点的权值积取模后等于k,如果存在多组点对,输出字典序最小的。
思路:
点分治模板题。按照套路,找重心,求出子树中节点到重心的权值积取模后的值dis[i](包括重心的权值,也不可以不包括,一样的),用id[j]记录该路径的端点,用的是点分治的第二种写法。递归时,用桶mine[i]记录到重心权值积为i的最小编号。然后查找时,对dis[j],满足要求的tmp为:tmp*dis[j]%MOD=k*V[u],因为我们的dis中包括重心的权值,所以重心的权值被乘了2次。然后用到了逆元,tmp=k*V[u]%MOD*inv[dis[j]]%MOD。更新完答案后就更新桶。
因为没看清题目,题目求得点对(a,b)是a<b,而我以为(a,a)也满足,然后就找了两小时bug,崩溃到想锤电脑QAQ...。
AC代码:
#include<cstdio> #include<algorithm> #include<cctype> #include<cstring> using namespace std; inline int read(){ int x=0,f=0;char ch=0; while(!isdigit(ch)) {f|=ch=='-';ch=getchar();} while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return f?-x:x; } typedef long long LL; const int maxn=1e5+5; const int MOD=1e6+3; const int maxk=1e6+5; const int inf=0x3f3f3f3f; struct node1{ int v,nex; }edge[maxn<<1]; struct node2{ int x,y; node2(){x=y=0;} node2(int x,int y):x(x),y(y){} }ans; bool operator < (node2 a,node2 b){ if(a.x==b.x) return a.y<b.y; return a.x<b.x; } int n,k,cnt,head[maxn],sz[maxn],mson[maxn],Min,root,size; int vis[maxn],mine[maxk],id[maxn],t,tt; LL V[maxn],dis[maxn],inv[maxk]; void init(){ inv[1]=1; for(int i=2;i<maxk;++i) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD; } void adde(int u,int v){ edge[++cnt].v=v; edge[cnt].nex=head[u]; head[u]=cnt; } void getroot(int u,int fa){ sz[u]=1,mson[u]=0; for(int i=head[u];i;i=edge[i].nex){ int v=edge[i].v; if(vis[v]||v==fa) continue; getroot(v,u); sz[u]+=sz[v]; mson[u]=max(mson[u],sz[v]); } mson[u]=max(mson[u],size-sz[u]); if(mson[u]<Min) Min=mson[u],root=u; } void getdis(int u,int fa,LL len){ dis[++t]=len,id[t]=u; for(int i=head[u];i;i=edge[i].nex){ int v=edge[i].v; if(vis[v]||v==fa) continue; getdis(v,u,len*V[v]%MOD); } } void solve(int u){ mine[V[u]]=u,t=0; for(int i=head[u];i;i=edge[i].nex){ int v=edge[i].v; if(vis[v]) continue; tt=t; getdis(v,u,V[u]*V[v]%MOD); for(int j=tt+1;j<=t;++j){ LL tmp=1LL*k*V[u]%MOD*inv[dis[j]]%MOD; if(mine[tmp]==inf) continue; node2 other; if(mine[tmp]<id[j]) other.x=mine[tmp],other.y=id[j]; else other.x=id[j],other.y=mine[tmp]; if(other<ans) ans=other; } for(int j=tt+1;j<=t;++j) mine[dis[j]]=min(mine[dis[j]],id[j]); } mine[V[u]]=inf; for(int i=1;i<=t;++i) mine[dis[i]]=inf; } void fenzhi(int u,int ssize){ vis[u]=1; solve(u); for(int i=head[u];i;i=edge[i].nex){ int v=edge[i].v; if(vis[v]) continue; Min=inf,root=0; size=sz[v]<sz[u]?sz[v]:(ssize-sz[u]); getroot(v,0); fenzhi(root,size); } } int main(){ init(); memset(mine,0x3f,sizeof(mine)); while(~scanf("%d%d",&n,&k)){ cnt=0; ans.x=ans.y=n+1; for(int i=0;i<=n;++i) head[i]=vis[i]=0; for(int i=1;i<=n;++i){ int tmp=read(); V[i]=tmp; } for(int i=1;i<n;++i){ int u=read(),v=read(); adde(u,v); adde(v,u); } Min=inf,root=0,size=n; getroot(1,0); fenzhi(root,n); if(ans.x==n+1) printf("No solution "); else printf("%d %d ",ans.x,ans.y); } return 0; }