UVA6642(树的点分治)

题意:给你一颗树,树上的每个顶点有一个权值,给定一个数k,让你找一条路径,使得这条路径上的点的权值的乘积模上一个数后等于k.


解题思路:这是一道树分治的经典题目,也是我做的第一道树分治的题目,这题的话比较简单,几乎模板,需要注意的地方是逆元要一次求出,还要注意一下hash的地方,写的太丑会t.


#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e6 + 10;
const LL mod = 1e6 + 3;
int N, K;
int E;
bool flag;
int Size, Maxn;
LL inv[maxn];//逆元
int head[maxn];
LL value[maxn];
int Hash[maxn];
bool visit[maxn];
pair<int, int> ans;
int dp[maxn];//以i为根的子树的节点数
int root;
vector<pair<int, LL> > temp;
struct edge{
    int v, Nxt;
}Edge[maxn<<1];
void add_edge(int u, int v)
{
    Edge[E].v = v;
    Edge[E].Nxt = head[u];
    head[u] = E++;
}
void init()
{
    memset(head, -1, sizeof(head));
    memset(visit, false, sizeof(visit));
    memset(Hash, -1, sizeof(Hash));
    flag = false;
    temp.clear();
    root = -1;
    E = 0;
}
LL quick_mod(LL x, LL i)
{
    LL ans = 1;
    ans %= mod;
    while(i)
    {
        if(i&1) ans = (ans * x) % mod;
        i >>= 1;
        x = (x * x) % mod;
    }
    return ans;
}
void getInv()
{
    for(int i = 1; i <= (int)mod; i++)
    {
        inv[i] = quick_mod((LL)i, mod - 2);
    }
}
void getRoot(int u, int fa)//找出树的重心
{
    dp[u] = 1;
    int Max = 0;
    for(int i = head[u]; i != -1; i = Edge[i].Nxt)
    {
        int v = Edge[i].v;
        if(v == fa) continue;
        if(!visit[v])
        {
            getRoot(v, u);
            dp[u] += dp[v];
            Max = max(Max, dp[v]);
        }
    }
    Max = max(Max, Size - dp[u]);
    if(Max < Maxn)
    {
        Maxn = Max;
        root = u;
    }
}
void getDis(int u, int fa, LL x)
{
    LL res = x * value[u] % mod;
    temp.push_back(make_pair(u, res));
    for(int i = head[u]; i != -1; i = Edge[i].Nxt)
    {
        int v = Edge[i].v;
        if(v == fa) continue;
        if(!visit[v])
        {
            getDis(v, u, res);
        }
    }
}
void update(int u, int v)
{
    if(u > v) swap(u, v);
    if(!flag)
    {
        flag = true;
        ans = make_pair(u, v);
    }
    else
    {
        if(u < ans.first) ans = make_pair(u, v);
        else if(u == ans.first && v < ans.second) ans = make_pair(u, v);
    }
}
LL d[maxn];
void work(int u)
{
    visit[u] = true;
    int cnt = 0;
    for(int i = head[u]; i != -1; i = Edge[i].Nxt)
    {
        int v = Edge[i].v;
        if(visit[v]) continue;
        temp.clear();
        getDis(v, v, value[u]);
        for(int j = 0; j < temp.size(); j++)
        {
            int id = temp[j].first;
            LL x = temp[j].second;
            if(x == K) update(id, u);
            LL judge = (inv[x] % mod * K) % mod;
            if(Hash[judge] == -1) continue;
            else
            {
                update(id, Hash[judge]);
            }
        }
        for(int j = 0; j < temp.size(); j++)
        {
            int id = temp[j].first;
            LL x = temp[j].second;
            x = (x * inv[value[u]]) % mod;
            d[++cnt] = x;
            if(Hash[x] == -1) Hash[x] = id;
            else
            {
                Hash[x] = min(Hash[x], id);
            }
        }
    }
    for(int i = 1; i <= cnt; i++) Hash[d[i]] = -1;
    for(int i = head[u]; i != -1; i = Edge[i].Nxt)
    {
        int v = Edge[i].v;
        if(visit[v]) continue;
        Maxn = dp[v];
        Size = dp[v];
        root = -1;
        getRoot(v, v);
        work(root);
    }
}

int main()
{
    getInv();
    while(~scanf("%d%d", &N, &K))
    {
        init();
        for(int i = 1; i <= N; i++)
        {
            scanf("%lld", &value[i]);
        }
        int u, v;
        for(int i = 1; i < N; i++)
        {
            scanf("%d%d", &u, &v);
            add_edge(u, v);
            add_edge(v, u);
        }
        Maxn = N;
        Size = N;
        getRoot(1, 1);
        work(root);
        if(flag) printf("%d %d\n", ans.first, ans.second);
        else printf("No solution\n");
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/creatorx/article/details/78323189