您的位置:首页 > 其它

HDU4812 D Tree(树的点分治)

2016-03-27 17:05 309 查看
题目大概说给一棵有点权的树,输出字典序最小的点对,使这两点间路径上点权的乘积模1000003的结果为k。

树的点分治搞了。因为是点权过根的两条路径的LCA会被重复统计,而注意到1000003是质数,所以这个用乘法逆元搞一下就OK了。还有要注意“治”的各个实现,把时间复杂度“控制”在O(nlogn)。

WA了几次,WA在漏了点到子树根的路径,还有每次分治忘了清空数组。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 111111
struct Edge{
int v,next;
}edge[MAXN<<1];
int NE,head[MAXN];
void addEdge(int u,int v){
edge[NE].v=v; edge[NE].next=head[u]; head[u]=NE++;
}
bool vis[MAXN];
int mini,cen,size[MAXN];
void getSize(int u,int fa){
size[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);
size[u]+=size[v];
}
}
void getCen(int u,int fa,int &tot){
int res=tot-size[u];
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(v==fa || vis[v]) continue;
getCen(v,u,tot);
res=max(res,size[v]);
}
if(res<mini) mini=res,cen=u;
}
int getCen(int u){
getSize(u,u);
mini=INF;
getCen(u,u,size[u]);
return cen;
}
long long ine(long long a){
long long res=1,n=1000001;
while(n){
if(n&1) res*=a,res%=1000003;
a*=a; a%=1000003;
n>>=1;
}
return res;
}
int n,k,val[MAXN];
int ansx,ansy;
int record[1000003],tn,tmpx[MAXN],tmpy[MAXN],all[MAXN],an;
void dfs(int u,int fa,long long dist,int &top){
int v=record[ine(dist)*k%1000003*top%1000003];
if(v){
if(u<v){
if(u<ansx) ansx=u,ansy=v;
else if(u==ansx && v<ansy) ansy=u,ansy=v;
}else{
if(v<ansx) ansx=v,ansy=u;
else if(v==ansx && u<ansy) ansy=v,ansy=u;
}
}
tmpx[tn]=u; tmpy[tn]=dist; ++tn;
all[an++]=dist;
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(v==fa || vis[v]) continue;
dfs(v,u,dist*val[v]%1000003,top);
}
}
void conquer(int u){
an=0;
all[an++]=val[u];
record[val[u]]=u;
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(vis[v]) continue;
tn=0;
dfs(v,v,(long long)val[u]*val[v]%1000003,val[u]);
for(int j=0; j<tn; ++j){
if(record[tmpy[j]]==0 || record[tmpy[j]]>tmpx[j]) record[tmpy[j]]=tmpx[j];
}
}
for(int i=0; i<an; ++i) record[all[i]]=0;
}
void divide(int u){
u=getCen(u);
vis[u]=1;
conquer(u);
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(vis[v]) continue;
divide(v);
}
}
int main(){
int a,b;
while(~scanf("%d%d",&n,&k)){
for(int i=1; i<=n; ++i){
scanf("%d",val+i);
}
NE=0;
memset(head,-1,sizeof(head));
for(int i=1; i<n; ++i){
scanf("%d%d",&a,&b);
addEdge(a,b);
addEdge(b,a);
}
memset(vis,0,sizeof(vis));
ansx=ansy=INF;
divide(1);
if(ansx==INF) puts("No solution");
else printf("%d %d\n",ansx,ansy);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: