您的位置:首页 > 其它

hdu 4670 Cube number on a tree

2014-06-12 10:44 399 查看


Cube number on a tree

Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)

Total Submission(s): 823 Accepted Submission(s): 149



Problem Description

The country Tom living in is famous for traveling. Every year, many tourists from all over the world have interests in traveling there.

There are n provinces in the country. According to the experiences from the tourists came before, every province has its own preference value. A route’s preference value from one province to another is defined as the product of all the preference value of the
provinces on the route. It’s guaranteed that for each two provinces in the country there is a unique route from one to another without passing any province twice or more.

Tom is a boy crazy about cube number. A cube number is a positive integer whose cube root is also an integer. He is planning to travel from a province to another in the summer vacation and he will only choose the route with the cube number preference value.
Now he want to know the number of routes that satisfy his strange requirement.



Input

The input contains several test cases, terminated by EOF.

Each case begins with a number n ( 1 ≤ n ≤ 50000), the number of the provinces.

The second line begins with a number K (1 ≤ K ≤ 30), and K difference prime numbers follow. It’s guaranteed that all the preference number can be represented by the product of some of this K numbers(a number can appear multiple times).

The third line consists of n integer numbers, the ith number indicating the preference value Pi(0 ≤ Pi ≤ 1015) of the i-th province.

Then n - 1 lines follow. Each line consists of two integers x, y, indicating there is a road connecting province x and province y.



Output

For each test case, print a number indicating the number of routes that satisfy the requirement.



Sample Input

5
3 2 3 5
2500 200 9 270000 27
4 2
3 5
2 5
4 1




Sample Output

1

在一棵树上,求多少条路径的点权值积为立方数,因为已经知道权值都是k个质数的幂乘积形式,所以可以把权值转化成一个三进制的数,这个数为0,则说明是立方数。点分治,假设当前根节点是root,当前正在处理root的某个儿子a,那么答案有两部分,a到其儿子的路径到a的兄弟的儿子节点的乘积是立方数,这个可以用map统计的,还有一部分就是a的儿子节点到root的乘积是立方数。
当然答案还有第三部分,那就是点权值本来就是立方数的。

#pragma comment(linker,"/STACK:102400000,102400000")
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <map>
#include <algorithm>
using namespace std;

typedef long long ll;
#define rep(i,s,t) for(int i=s;i<t;i++)
#define red(i,s,t) for(int i=s-1;i>=t;i--)
#define ree(i,now) for(int i=head[now];i!=-1;i=edge[i].next)
#define clr(a,v) memset(a,v,sizeof a)

const int N=50005;
const int K=33;
struct Edge{
    int v,next;
}edge[N*2];
int head
,e;

int Num
[K];
int son
,MaxSize;
int root,all;
int n,k,a[K],d[K],x,y,cnt;
ll v
,dis
,three[K],mark
;
int Ans;
bool vis
;
map<ll,int>mp,mpp;

inline void Init(){
    three[0]=1;
    rep(i,1,K) three[i]=three[i-1]*3;
}

inline int getPos(ll v,int x){
    return v%three[x+1]/three[x];
}

inline ll get(ll val,int *x){
    ll ans=0;
    rep(i,0,k) ans+=((getPos(val,i)+x[i])%3)*three[i];
    return ans;
}

inline void getCh(ll b,int i){
    bool ok=1;
    mark[i]=0;
    if(b==0)return;
    rep(j,0,k){
        Num[i][j]=0;
        while(b>1 && b%a[j]==0){
            Num[i][j]++;
            b/=a[j];
        }
        Num[i][j]%=3;
        mark[i]+=three[j]*Num[i][j];
        if(Num[i][j]!=0) ok=0;
    }
    if(ok) Ans++;
}

inline void addEdge(int u,int v){
    edge[e].v=v;
    edge[e].next=head[u];
    head[u]=e++;
}

inline void In(){
    scanf("%d",&k);
    rep(i,0,k) scanf("%d",&a[i]);
    rep(i,1,n+1){
        scanf("%I64d",&v[i]);
        getCh(v[i],i);
    }
    clr(head,-1),e=0;
    rep(i,1,n){
        scanf("%d%d",&x,&y);
        addEdge(x,y);addEdge(y,x);
    }
    clr(vis,0);
}

inline void dfs_Size(int now,int pre){
    all++;
    ree(i,now){
        int nxt=edge[i].v;
        if(!vis[nxt] && nxt!=pre) dfs_Size(nxt,now);
    }
}

inline void dfs_Root(int now,int pre){
    int Max=0;
    son[now]=0;
    ree(i,now){
        int nxt=edge[i].v;
        if(!vis[nxt] && pre!=nxt){
            dfs_Root(nxt,now);
            son[now]+=son[nxt]+1;
            if(son[nxt]+1>Max) Max=son[nxt]+1;
        }
    }
    int res=all-son[now]-1;
    if(Max<res) Max=res;
    if(Max<MaxSize){
        MaxSize=Max;root=now;
    }
}

inline ll Val(int *c){
    ll ans=0;
    rep(j,0,k) ans+=c[j]*three[j];
    return ans;
}

inline ll Transform(ll a,ll b){
    ll ans=0;
    rep(j,0,k) ans+=(getPos(a,j)+getPos(b,j))%3*three[j];
    return ans;
}
inline void dfs_Dis(int now,int pre,ll val){
    dis[cnt++]=val;
    ree(i,now){
        int nxt=edge[i].v;
        if(!vis[nxt] && nxt!=pre){
            dfs_Dis(nxt,now,Transform(val,mark[nxt]));
        }
    }
}

inline ll Suit(ll v){
    ll ans=0;
    rep(i,0,k){
        int x=getPos(v,i);
        int y=(3-x)%3;
        ans+=three[i]*y;
    }
    return ans;
}

inline void Work(int now){
    all=0;
    dfs_Size(now,-1);
    MaxSize=n+10;
    dfs_Root(now,-1);
    vis[root]=1;
    mp.clear();
    ree(i,root){
        int nxt=edge[i].v;cnt=0;
        if(vis[nxt]) continue;
        dfs_Dis(nxt,root,mark[nxt]);
        rep(j,0,cnt){
            int vv=mp[Suit(dis[j])];
            if(vv) Ans+=vv;
        }
        rep(j,0,cnt){
            ll p=get(dis[j],Num[root]);
            if(p==0) Ans++;
            mp[p]++;
        }
    }
    ree(i,root){
        int nxt=edge[i].v;
        if(!vis[nxt]){
            Work(nxt);
        }
    }
}

inline void app(){
    freopen("1.txt","w",stdout);
    int a[]={2,3,5,7,11,13,17,19,23,29};
    rep(j,0,10){
        printf("3000 10 2 3 5 7 11 13 17 19 23 29\n");
        rep(i,0,3000) printf("%d ",a[rand()%10]);
        rep(i,1,3000) printf("%d 1\n",i+1);
    }
}

int main(){
    //app();/*
    //freopen("1.txt","r",stdin);
    Init();
    while(~scanf("%d",&n)){
        Ans=0;
        In();
        Work(1);
        printf("%d\n",Ans);
    }
    return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: