HDU - 4670 (点分治 + 状压 + map(卡unordered_map))

Cube number on a tree

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 P i(0 ≤ P i ≤ 10 15) 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

题意: 一棵树,每个点都有一个 val,问有多少对 (u,v) 满足 u 到 v 的路径上的点权积是立方数。

Analyse: 关于立方数的问题,由题目易知可以用质因子的个数来表示,并且质因子的种类最多30种。那么每种质因子个数对 3 取模,然后用三进制状压即可。如三进制数为 0 ,那么很显然就是立方数。
剩下的就是比较简单的点分治问题。
值得注意的一点是,这个题不能用 unordered_map,由于会频繁的 clear() 与重建,unordered_map 的建立并不快。

Code:



#include<bits/stdc++.h>
#define debug(x) cerr << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a, b) memset((a),b,sizeof(a))
#define rep(i, a, b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define fi first
#define se second
#define ptch putchar
#define CLR(a) while(!(a).empty()) a.pop()

using namespace std;

#ifndef ONLINE_JUDGE
clock_t prostart = clock();
#endif

const int maxn = 5e4 + 100;
const int inf = 0x3f3f3f3f;
int head[maxn], cnt, n, k;
struct xx {
    int v, nex;
} edge[maxn * 2];
int sonnum[maxn];
bool vis[maxn];
LL ans, pri[35];

struct node {
    int Num[35];

    void init() {
        clr(Num,0);
    }
} val[maxn];

vector<node> dis;
map<LL, int> have;

void init() {
    for (int i = 0; i <= n + 5; ++i) {
        head[i] = -1;
        vis[i] = false;
        val[i].init();
    }
    cnt = 0;
    ans = 0;
}

void Tree_Center(int &mi, int &rt, int p, int fa, int sum) {
    int maxx = 0;
    sonnum[p] = 1;
    for (int i = head[p]; ~i; i = edge[i].nex) {
        int v = edge[i].v;
        if (vis[v] || v == fa) continue;
        Tree_Center(mi, rt, v, p,sum);
        sonnum[p] += sonnum[v];
        maxx = max(maxx,sonnum[v]);
    }
    if (mi > max(maxx, sum - sonnum[p])) {
        mi = max(maxx, sum - sonnum[p]);
        rt = p;
    }
}

LL getHash(node sta) {
    LL tmp = 1, Hash = 0;
    for (int i = 0; i < k; ++i) {
        Hash += tmp * sta.Num[i];
        tmp *= 1LL * 3;
    }
    return Hash;
}

node addSta(node a, node b) {
    node tmp_sta;
    for (int i = 0; i < k; ++i) {
        tmp_sta.Num[i] = (a.Num[i] + b.Num[i]) % 3;
    }
    return tmp_sta;
}

void Tree_dis(int p,int fa,node sta,node beg){
    dis.pb(sta);
    node tmp_sta;
    for(int i = 0;i < k;++ i){
        tmp_sta.Num[i] = (3 - sta.Num[i] + beg.Num[i]) % 3;
    }
    LL _find = getHash(tmp_sta);
    if(have.count(_find))
        ans += have[_find];
    if(getHash(sta) == 0) ++ ans;
    for(int i = head[p]; ~i;i = edge[i].nex){
        int v = edge[i].v;
        if(vis[v] || v == fa) continue;
        Tree_dis(v,p,addSta(sta,val[v]),beg);
    }
}

void dfs(int p, int fa) {
    int mi = inf,rt;
    Tree_Center(mi,rt,p,fa,sonnum[p]);
    have.clear();
    vis[rt] = 1;
    for(int i = head[rt]; ~i;i = edge[i].nex){
        int v = edge[i].v;
        if(vis[v]) continue;
        dis.clear();
        Tree_dis(v,rt,addSta(val[v],val[rt]),val[rt]);
        for(int i = 0;i < dis.size();++ i){
            ++ have[getHash(dis[i])];
        }
    }
    for(int i = head[rt]; ~i;i = edge[i].nex){
        int v = edge[i].v;
        if(vis[v] || v == fa) continue;
        dfs(v,rt);
    }
}

int main() {
#ifndef ONLINE_JUDGE
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
#endif

    while (~scanf("%d%d", &n,&k)) {
        init();
        for (int i = 0; i < k; ++i) {
            scanf("%lld",&pri[i]);
        }
        for (int i = 1; i <= n; ++i) {
            LL tmp; scanf("%lld",&tmp);
            for (int j = 0; j < k; ++j) {
                while (tmp % pri[j] == 0) {
                    ++ val[i].Num[j];
                    tmp /= pri[j];
                }
                val[i].Num[j] %= 3;
            }
            if(getHash(val[i]) == 0) ++ ans;
        }
        for (int i = 1; i < n; ++i) {
            int u,v; scanf("%d%d",&u,&v);
            edge[cnt] = xx{v, head[u]};
            head[u] = cnt++;
            edge[cnt] = xx{u, head[v]};
            head[v] = cnt++;
        }
        sonnum[1] = n;
        dfs(1, -1);
        printf("%lld\n", ans);
    }

#ifndef ONLINE_JUDGE
    cerr << "time: " << 1.0 * (clock() - prostart) / CLOCKS_PER_SEC << " s" << endl;
#endif
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值