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

      

  • 相关阅读:
    ASP.NET MVC 4 中Jquery上传插件Uploadify简单使用-版本:3.2.1
    EasyUI Accordion下的Panel面板初始化时全部折叠
    找回windows 8 中隐藏的Aero Lite主题
    冒泡排序
    sqlserver中常用的四个选项(NOCOUNT/ANSI_NULLS/QUOTED_IDENTIFIER/ XACT_ABORT)
    ASP.NET MVC 传递数据 从前台到后台,包括单个对象,多个对象,集合
    ASP.NET MVC Bundle使用 合并压缩
    Code First Migrations
    Android系统开发--灯光系统之电池灯的流程分析
    Android系统--灯光系统驱动编写
  • 原文地址:https://www.cnblogs.com/Przz/p/5812343.html
Copyright © 2011-2022 走看看