zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    React 16 源码瞎几把解读 【前戏】 为啥组件外面非得包个标签?
    nodejs 使用redis 管理session
    nodejs 优雅的连接 mysql
    mongodb 学习笔记 3 --- 查询
    mongodb 学习笔记 2 --- 修改器
    mongodb 学习笔记--- 基础知识
    看jquery3.3.1学js类型判断的技巧
    FIS3 大白话【一】
    Flutter 插件开发:以微信SDK为例
    最新Android面试题整理,收藏下吧值得拥有!
  • 原文地址:https://www.cnblogs.com/Przz/p/5812343.html
Copyright © 2011-2022 走看看