• 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;
    }
    

      

  • 相关阅读:
    80端口被NT kernel & System 占用pid 4的解决方法 80端口被占用
    Linux:linux输入输出重定向、管道命令grep/wc、linux进程管理ps、pstree、kill命令、linux防火墙命令firewall-cmd、防火墙开启关闭端口号
    Linux:Linu文件权限管理、文件权限修改chmod、修改属主属组chown、特殊权限SUID、SGID、Sticky、umask
    [Java]获取图片高和宽
    [Java]获取Window界面的标题栏的高度大小
    [算法 笔记]字符串表达式计算(简易版)
    [算法 笔记]大数相乘(续)
    [算法 笔记]2014年去哪儿网 开发笔试(续)第一题BUG修正
    [算法 笔记]堆排序(续)
    [算法 笔记]用小范围随机函数编写大范围随机函数
  • 原文地址:https://www.cnblogs.com/Przz/p/5812343.html
Copyright © 2020-2023  润新知