HDU 4812 D Tree (树分治之点分治)

题目大意:

给出一棵树, 顶点数 n <= 100000

每个点有一个权值

给出K

询问这棵树中两点路径上的点的权值乘积对1e6 + 3取模之后等于K的路径的两个端点形成的点对中字典序最小的


大致思路:

点分治第二题

用f[i]表示从当前的子树根开始到某个点的路径乘积为i的点的最小标号

于是对于每一次分治, 去掉重心x之后, 依次处理每一棵子树来使得f的来源不一样

注意要预处理逆元


代码如下:

Result  :  Accepted     Memory  :  24420 KB     Time :  2823 ms

/*
 * Author: Gatevin
 * Created Time:  2015/10/14 9:59:26
 * File Name: Sakura_Chiyo.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

#define maxn 100010

struct Edge
{
    int u, v, nex;
    Edge(){}
    Edge(int _u, int _v, int _nex)
    {
        u = _u, v = _v, nex = _nex;
    }
};

Edge edge[maxn << 1];
int head[maxn];
int E;
int n;

void add_Edge(int u, int v)
{
    edge[++E] = Edge(u, v, head[u]);
    head[u] = E;
}

int del[maxn];
int root;
int mx[maxn];
int size[maxn];
int mi;
int N;
lint K;
lint w[maxn];
const lint mod = 1e6 + 3;
pair<int, int> ans;
lint rev[1000010];

void getRev()
{
    rev[1] = 1;
    for(lint i = 2; i < mod; i++)
        rev[i] = (mod - mod / i) * rev[mod % i] % mod;
}

void dfs_size(int now, int father)
{
    size[now] = 1;
    mx[now] = 1;
    for(int i = head[now]; i + 1; i = edge[i].nex)
    {
        int v = edge[i].v;
        if(v != father && !del[v])
        {
            dfs_size(v, now);
            size[now] += size[v];
            if(size[v] > mx[now]) mx[now] = size[v];
        }
    }
}

void dfs_root(int r, int now, int father)
{
    if(size[r] - size[now] > mx[now]) mx[now] = size[r] - size[now];
    if(mx[now] < mi) mi = mx[now], root = now;
    for(int i = head[now]; i + 1; i = edge[i].nex)
    {
        int v = edge[i].v;
        if(v != father && !del[v]) dfs_root(r, v, now);
    }
}

lint f[1000010];//f[i]表示距离为i的字典序最小的点的标号+pre
const pair<int, int> inf = make_pair(1e9, 1e9);
lint pre;
const lint bit = 1e5;

void get(int now, int father, lint dis, int flag)
{
    dis = dis*w[now] % mod;
    if(flag == 1)
    {
        //dis*x % mod = K -> x = K*dis^(mod - 2) % mod
        if(f[K*rev[dis] % mod] > pre)
        {
            int other = (int)(f[K*rev[dis] % mod] - pre);
            pair<int, int> p = other < now ? make_pair(other, now) : make_pair(now, other);
            if(ans > p) ans = p;
        }
    }
    else
    {
        if(f[dis] <= pre) f[dis] = pre + now;
        else f[dis] = min(f[dis], pre + now);
    }
    for(int i = head[now]; i + 1; i = edge[i].nex)
    {
        int v = edge[i].v;
        if(!del[v] && v != father)
            get(v, now, dis, flag);
    }
}


void dfs(int now)
{
    mi = N;
    dfs_size(now, 0);
    dfs_root(now, now, 0);
    del[root] = 1;
    pre += bit;
    f[w[root]] = pre + root;//pre是因为每次清空f数组是不现实的, 于是用pre/bit表示第几次
    for(int i = head[root]; i + 1; i = edge[i].nex)
    {
        int v = edge[i].v;
        if(!del[v])
        {
            get(v, root, 1, 1);
            get(v, root, w[root], 0);
        }
    }
    for(int i = head[root]; i + 1; i = edge[i].nex)
    {
        int v = edge[i].v;
        if(!del[v]) dfs(v);
    }
}

void solve()
{
    ans = inf;
    //pre = 0
    //memset(f, 0, sizeof(f));利用pre不清0, f就可以不清0了
    dfs(1);
    if(ans == inf) puts("No solution");
    else printf("%d %d\n", ans.first, ans.second);
}

int main()
{
    getRev();//预处理逆元
    pre = 0;
    while(scanf("%d %I64d", &N, &K) != EOF)
    {
        E = 0;
        memset(head, -1, sizeof(head));
        memset(del, 0, sizeof(del));
        
        for(int i = 1; i <= N; i++)
            scanf("%I64d", &w[i]);
        int u, v;
        for(int i = 1; i < N; i++)
        {
            scanf("%d %d", &u, &v);
            add_Edge(u, v);
            add_Edge(v, u);
        }
        solve();
    }
    return 0;
}




Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值