hdu 4670 Cube number on a tree(点分治)

Cube number on a tree

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 1628    Accepted Submission(s): 382


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
hdu 4670 Cube number on a tree(点分治)

problem:
在一棵树上,求多少条路径的点权值积为立方数

solve:
和普通的求积为k的点对数很像.因为权值有10^15,所以用质因子来记录每个树的权值. 然后就是状态保存,因为当你知道当前子树的一条链时
,需要查找其它子树(同一根)是否有链与其对应使积为立方数. 质因子总共有30位,所以可以用一个longlong来记录状态,用map保存
(递归所有重心,每次计算当前重心的所有情况)

hhh-2016-08-24 09:42:56
*/
#pragma comment(linker,"/STACK:124000000,124000000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <math.h>
#include <map>
#define lson  i<<1
#define rson  i<<1|1
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define scanfi(a) scanf("%d",&a)
#define scanfl(a) scanf("%I64d",&a)
#define key_val ch[ch[root][1]][0]
#define inf 0x3FFFFFFFFFFFFFFFLL
#define mod 1000003
using namespace std;
const ll xo = (1LL << 61)-1;
const int maxn = 50010;
int head[maxn];
int n,k,s[maxn],f[maxn],root;
int Size,tot;
bool vis[maxn];
ll factor[maxn][31],d[maxn][31],fac[31];
int facnt;
int id[maxn];
ll val;
struct node
{
    int to;
    int next;
} edge[maxn << 2];

void ini()
{
    clr(factor,0);
    clr(head,-1),clr(vis,0);
    clr(s,0);
    tot = 0;
}


void add_edge(int u,int v)
{
    edge[tot].to = v,edge[tot].next = head[u],head[u] = tot++;
}


void get_root(int now,int fa)
{
    int v;
    s[now] = 1,f[now] = 0;
    for(int i = head[now]; ~i; i = edge[i].next)
    {
        if((v=edge[i].to) == fa || vis[v])
            continue;
        get_root(v,now);
        s[now] += s[v];
        f[now] = max(f[now],s[v]);
    }
    f[now] = max(f[now],Size-s[now]);
    if(f[now] < f[root]) root = now;
}
int num;
map<ll,ll> mp;
ll make_hash(ll q[])
{
    ll t = 0;

    for(int i = 0; i < facnt; i++)
    {
        t = t*3LL + q[i];
    }

    return t;
}

void dfs(int now,int fa)
{
    int v;
    id[num++] = now;
    s[now] = 1;

    for(int i = head[now]; ~i; i = edge[i].next)
    {
        if( (v=edge[i].to) == fa || vis[v])
            continue;
        for(int j = 0; j < facnt; j++)
        {
            d[v][j] = (factor[v][j]+d[now][j])%3;
        }
        dfs(v,now);
        s[now] += s[v];
    }
}
ll ans = 0;
ll tp[31];
void Debug(ll t)
{
    for(int i = 30; i >= 0; i--)
    {
        if(t & (1 << i))
            printf("1");
        else
            printf("0");
    }
    cout << endl;
}
void make_ans(int now,int cnt)
{
    int v ;
    f[0] = Size = cnt;
    get_root(now,root = 0);
    vis[root] = 1;
    mp.clear();
    ll ts = make_hash(factor[root]);
    if(ts == 0)
        ans ++;

    for(int i = head[root]; ~i; i = edge[i].next)
    {
        if(vis[v = edge[i].to])
            continue;
        num = 0;
        for(int j = 0; j < facnt; j++)
            d[v][j] = factor[v][j];
        dfs(v,root);


        for(int j = 0; j < num; j++)
        {
            for(int t = 0; t < facnt; t++)
            {
                tp[t] = (d[id[j]][t] + factor[root][t])%3;
            }
            ll ta = make_hash(tp);

            if(ta == 0)
            {
                ans ++;
            }

            ta  = 0;
            for(int t = 0; t < facnt; t++)
                ta = ta*3LL + (3LL-tp[t])%3;
            if(mp[ta] > 0)
            {
                ans += mp[ta];
            }
        }
        for(int j = 0; j < num; j++)
        {
            ll ta = make_hash(d[id[j]]);
            if(mp[ta] == -1)
                mp[ta] = 0;
            mp[ta] ++;
        }
    }
    for(int i = head[root]; ~i; i = edge[i].next)
    {
        if(vis[v = edge[i].to])
            continue;
        make_ans(v,s[v]);
    }
}
void make_fac(int u,ll cur)
{
    ll t = cur;
    for(int i = 0; i < facnt; i++)
    {
        while(t % fac[i] == 0)
        {
            t /= fac[i];
            factor[u][i]++;
        }
        factor[u][i] %= 3;
    }
}

int main()
{
    int n,u,v;
//    freopen("in.txt","r",stdin);
    while( scanfi(n) != EOF)
    {
        ini();
        scanfi(facnt);
        for(int i = 0; i < facnt; i++)
            scanfl(fac[i]);
        for(int i = 1; i<= n; i++)
        {
            scanfl(val);
            make_fac(i,val);

        }
        for(int i = 1; i < n; i++)
        {
            scanfi(u),scanfi(v);
            add_edge(u,v);
            add_edge(v,u);
        }
        ans =0;
        make_ans(1,n);
        printf("%I64d
",ans);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/Przz/p/5812343.html