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\n",ans);
    }
    return 0;
}

  

时间: 2024-10-10 07:32:42

hdu 4670 Cube number on a tree(点分治)的相关文章

HDU 4670 Cube number on a tree ( 树的点分治 )

题意 : 给你一棵树 . 树的每一个结点都有一个权值 . 问你有多少条路径权值的乘积是一个全然立方数 . 题目中给了你 K 个素数 ( K <= 30 ) , 全部权值都能分解成这k个素数 思路 : 一个全然立方数的素因子个数都是三的倍数 , 所以我们仅仅要求各个素数的个数即可了 , 而且我们仅仅关心个数对三的余数 所以我们能够用一个 长整形来表示每一个结点到根的各个素因子的个数( 三进制压缩 ) . 只是由于用位运算会快一点 , 所以我用了四进制.即每两位表示一个素因子的个数 . 中间合并的时

hdu4670 Cube number on a tree 点分治

这次写不容斥的版本,WA了好几次,又改成容斥的,还是没过,一怒之下把所有的int改成longlong就过了... #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<map> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(

【点分治】hdu4670 Cube number on a tree

求树上点权积为立方数的路径数. 显然,分解质因数后,若所有的质因子出现的次数都%3==0,则该数是立方数. 于是在模意义下暴力统计即可. 当然,为了不MLE/TLE,我们不能存一个30长度的数组,而要压成一个long long. 存储状态用map即可,貌似哈希表可以随便卡掉……? 手动开栈……当然这样有可能MLE,所以还得改一些BFS…… <法一>map: #pragma comment(linker, "/STACK:1024000000,1024000000") #in

hdu 2665 Kth number(划分树)

Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4602 Accepted Submission(s): 1468 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first l

HDU 4718 The LCIS on the Tree(树链剖分)

Problem Description For a sequence S1, S2, ... , SN, and a pair of integers (i, j), if 1 <= i <= j <= N and Si < Si+1 < Si+2 < ... < Sj-1 < Sj , then the sequence Si, Si+1, ... , Sj is a CIS(Continuous Increasing Subsequence). The

HDU - 3584 Cube (三维树状数组 + 区间改动 + 单点求值)

HDU - 3584 Cube Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Status Description Given an N*N*N cube A, whose elements are either 0 or 1. A[i, j, k] means the number in the i-th row , j-th column and k-th layer. I

HDU 3584 Cube (三维 树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3584 Cube Problem Description Given an N*N*N cube A, whose elements are either 0 or 1. A[i, j, k] means the number in the i-th row , j-th column and k-th layer. Initially we have A[i, j, k] = 0 (1 <= i, 

HDU - 3584 Cube (三维树状数组 + 区间修改 + 单点求值)

HDU - 3584 Cube Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Status Description Given an N*N*N cube A, whose elements are either 0 or 1. A[i, j, k] means the number in the i-th row , j-th column and k-th layer. I

HDU 1988 Cube Stacking (数据结构-并查集)

Cube Stacking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 18900   Accepted: 6568 Case Time Limit: 1000MS Description Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start w