HDU4670 cube number on a tree(点分治+三进制加法)

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 P i(0 ≤ P i ≤ 10 15) 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


题解:


题意:给你一棵树,给你一些素数,给你每个点一个权值且每个权值均可由这些素数组成。现在定义任意任意两点的价值为他们路径上的权值相乘。求这样的点对的权值为立方数的个数
如果直接求得话会超int64,不可行
由立方数的性质可得,一个数可有素数组成,对于这些素数可以分解为这些素数相乘的形式如,24=(2^3)*(3^1);如果是立方数的话那么他的各进制对3取余都为0.股24可写成01这种三进制形式
对于这些权值的乘法可有三进制想加可得。
接下来就是树的分治了
当然这里可以先求出一条子树上的各个点的权值乘积,然后和根节点和其他字树比较看是否可以互补那么就找到一对
可用map容器实现。因为他重点是比较到根节点和其他子树是否可以互补,进而递归下去,求出每个子树的这样的点对


参考代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fi first
#define se second
#define pii pair<int,int>
#define pil pair<int,ll>
#define mkp make_pair
#define pb push_back
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3fll;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
const int maxn=1e5+10;
ll n,k,head[maxn],tot,root,siz[maxn];
ll h[maxn][40],pri[40],fa[maxn],mx[maxn],S;
ll dep,ch[maxn][40],fp[maxn],minn,nn;
bool vis[maxn];
map<ll,ll> mp;
struct Edge{
    int v,nxt;
} edge[maxn<<1];

inline void Init()
{
    tot=0;
    memset(head,-1,sizeof(head));
    memset(h,0,sizeof(h));
    memset(mx,0,sizeof(mx));
    memset(siz,0,sizeof(siz));
    memset(vis,false,sizeof(vis));
}

inline void AddEdge(ll u,ll v)
{
    edge[tot].v=v;
    edge[tot].nxt=head[u];
    head[u]=tot++;
}

inline void dfs1(ll u,ll fa)
{
    nn++;
    for(int e=head[u];~e;e=edge[e].nxt)
    {
        ll v=edge[e].v;
        if(v==fa||vis[v]) continue;
        dfs1(v,u);
    }
}

inline void GetRoot(ll u,ll fa)
{
    siz[u]=1;
    ll tit=0;
    for(ll e=head[u];~e;e=edge[e].nxt)
    {
        ll v=edge[e].v;
        if(v==fa||vis[v]) continue;
        GetRoot(v,u);
        siz[u]+=siz[v];
        tit=max(tit,siz[v]);
    }
    tit=max(tit,nn-siz[u]);
    if(tit<minn) minn=tit,root=u;
}
inline void dfs2(ll u,ll fa)
{
    //cout<<"dfs2"<<endl;
    if(fa==-1)
    {
         for(ll i=1;i<=k;++i)
            ch[dep][i]=h[u][i];
    }
    else
    {
        ll e=fp[fa];
        for(ll i=1;i<=k;++i)
            ch[dep][i]=(h[u][i]+ch[e][i])%3;
    }
    fp[u]=dep++;
    for(ll e=head[u];~e;e=edge[e].nxt)
    {
        ll v=edge[e].v;
        if(v!=fa&&!vis[v]) dfs2(v,u);
    }
}

inline ll work(ll u)
{
    ll s1=0,ans=0;
    mp.clear();
    for(ll i=1;i<=k;++i) s1=s1*3+h[u][i];
    if(s1==0) ans++;
    mp[s1]=1;
    for(ll e=head[u];~e;e=edge[e].nxt)
    {
        ll v=edge[e].v;
        if(vis[v]) continue;
        dep=0;dfs2(v,-1);
        for(ll i=0;i<dep;++i)
        {
            s1=0;
            for(ll j=1;j<=k;++j)
                s1=s1*3+(3-ch[i][j])%3;
            ans+=mp[s1];
        }
        for(ll i=0;i<dep;++i)
        {
            s1=0;
            for(ll j=1;j<=k;++j)
                s1=s1*3+(ch[i][j]+h[u][j])%3;
            mp[s1]++;
        }
    }
    return ans;
}

inline ll dfs(ll u)
{
    nn=0,minn=inf;
    dfs1(u,-1);
    GetRoot(u,-1);
    vis[root]=1;
    ll ans=work(root);
    for(ll e=head[root];~e;e=edge[e].nxt)
    {
        ll v=edge[e].v;
        if(vis[v]) continue;
        ans+=dfs(v);
    }
    return ans;
}

int main()
{
    while(~scanf("%lld",&n))
    {
        Init();
        k=read();
        for(ll i=1;i<=k;++i) pri[i]=read();

        for(ll i=1;i<=n;++i)
        {
            ll kk,val=read();
            for(ll j=1;j<=k;++j)
            {
                kk=0;
                while(val%pri[j]==0)
                {
                    ++kk;
                    val/=pri[j];
                    kk%=3;
                }
                h[i][j]=kk;
            }
        }
        for(ll i=1;i<n;++i)
        {
            ll x,y;
            x=read();y=read();
            AddEdge(x,y);AddEdge(y,x);
        }
        //cout<<"1"<<endl;
        printf("%lld
",dfs(1));
    }

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/csushl/p/11349137.html