• HDU4812 D tree 【点分治 + 乘法逆元】


    D树

    时间限制:10000/5000 MS(Java / Others)内存限制:102400/102400 K(Java / Others)
    总共提交5400个已接受的提交1144


    问题描述
    南京理工大学的操场上站着一棵高大的树。在树的每个分支上是一个整数(树可以被看作是一个有N个顶点的连通图,而每个分支可以被当作一个顶点)。今天,树下的学生正在考虑一个问题:我们可以在树上找到这样一个链,使链上所有整数(mod 10 6 + 3)的乘积等于K?
    你能帮助他们解决这个问题吗?
     

    输入
    有几个测试用例,请处理,直到EOF。
    每个测试用例都以包含两个整数N(1 <= N <= 10 5)和K(0 <= <<10 6 + 3)的行开始。下面一行包含n个数字v i(1 <= v i <10 6 + 3),其中vi表示顶点i上的整数。然后遵循N - 1行。每行包含两个整数x和y,表示顶点x和顶点y之间的无向边。
     

    产量
    对于每个测试用例,打印一个单行,其中包含两个整数a和b(其中a <b),表示链的两个端点。如果存在多个解决方案,请打印词典上最小的一个。如果没有解决方案,请打印“无解”(不含引号)。
    欲了解更多信息,请参阅下面的示例输出。
     

    示例输入
    5 60 2 5 2 3 3 1 2 1 3 2 4 2 5 5 2 2 5 2 3 3 1 2 1 3 2 4 2 5
     

    示例输出
    3 4 没有解决方案
    暗示
    1.“请按字典顺序打印最小的一个”。是指:先按照第一个数字的大小进行比较,若第一个数字大小相同,则按照第二个数字大小进行比较,依次类别。 2.若出现栈溢出,推荐使用C ++语言提交,并通过以下方式扩栈: #pragma comment(linker,“/ STACK:102400000,102400000”)



    点分治

    这种树上找路径问题最容易想到的就是点分治

    点治的思想其实很简单,分别以每个点为根,找出所有经过根的路径更新答案

    由于路径是一个二维的量,直接枚举是O(n^2),而点分治通过固定一个根而使问题简化为一维O(n)

    而由于树的性质,只要我们每次求出重心就可以保证最多只有logn层

    总的复杂度就成了O(每一层操作复杂度 * logn)一般都是O(nlogn)或O(nlog^2n)

    然而我点分治还是很生疏【我还是太弱了】


    对于这道题,我们需要找到两条路径权值乘积取模为K

    对于x * y ≡ K (mod P),可以化为x ≡ K/y (mod P)

    所以我们只需开一个hash表存x的值,对于每个y,用K乘上y的逆元查表更新答案就好了

    要注意的细节就是根节点也要算上,而且查找与更新的路径只能有一个经过根,也就是算y时不算上,而算x存表时算上根


    继续练习吧

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
    using namespace std;
    const int maxn = 100005,maxm = 200005,INF = 1000000000;
    const LL P = 1000003;
    inline int RD(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
    	return out * flag;
    }
    int N,K,V[maxn],Siz[maxn],F[maxn],vis[maxn],rt,sum,ansx,ansy;
    LL Hash[P],tmp[maxn],d[maxn],id[maxn],inv[P],cnt = 0;
    int head[maxn],nedge = 0;
    struct EDGE{int to,next;}edge[maxm];
    inline void build(int u,int v){
    	edge[nedge] = (EDGE){v,head[u]}; head[u] = nedge++;
    	edge[nedge] = (EDGE){u,head[v]}; head[v] = nedge++;
    }
    void getRT(int u,int fa){
    	int to; Siz[u] = 1; F[u] = 0;
    	Redge(u) if (!vis[to = edge[k].to] && to != fa){
    		getRT(to,u);
    		Siz[u] += Siz[to];
    		F[u] = max(F[u],Siz[to]);
    	}
    	F[u] = max(F[u],sum - Siz[u]);
    	if (F[u] < F[rt]) rt = u;
    }
    inline void query(int x,int u){
    	x = 1ll * inv[x] * K % P;
    	int v = Hash[x];
    	if (!v) return;
    	if (v < u) swap(u,v);
    	if (u < ansx || (u == ansx && v < ansy))
    		ansx = u,ansy = v;
    }
    void dfs(int u,int fa){
    	tmp[++cnt] = d[u]; id[cnt] = u; int to;
    	Redge(u) if (!vis[to = edge[k].to] && to != fa){
    		d[to] = 1ll * V[to] * d[u] % P;
    		dfs(to,u);
    	}
    }
    void solve(int u){
    	int to; vis[u] = true; Hash[V[u]] = u;
    	Redge(u) if (!vis[to = edge[k].to]){
    		cnt = 0; d[to] = V[to];
    		dfs(to,u);
    		REP(i,cnt) query(tmp[i],id[i]);
    		cnt = 0; d[to] = 1ll * V[to] * V[u] % P;
    		dfs(to,u);
    		REP(i,cnt) if (!Hash[tmp[i]] || Hash[tmp[i]] > id[i]) Hash[tmp[i]] = id[i];
    	}
    	Hash[V[u]] = 0;
    	Redge(u) if (!vis[to = edge[k].to]){
    		cnt = 0; d[to] = 1ll * V[to] * V[u] % P;
    		dfs(to,u);
    		REP(i,cnt) Hash[tmp[i]] = 0;
    	}
    	Redge(u) if (!vis[to = edge[k].to]){
    		sum = Siz[to]; F[rt = 0] = INF;
    		getRT(to,rt);
    		solve(rt);
    	}
    }
    void init(){
    	memset(vis,0,sizeof(vis));
    	memset(head,-1,sizeof(head)); nedge = 0; ansx = ansy = INF;
    	REP(i,N) V[i] = RD() % P;
    	REP(i,N - 1) build(RD(),RD());
    }
    void INIT(){
    	inv[1] = 1;
    	for (int i = 2; i < P; i++){
    		inv[i] = ((P - P / i) * inv[P % i] % P + P) % P;
    	}
    }
    int main(){
    	INIT();
    	while (~scanf("%d%d",&N,&K)){
    		init();
    		F[rt = 0] = INF; sum = N;
    		getRT(1,rt);
    		solve(rt);
    		if (ansx == INF) printf("No solution
    ");
    		else printf("%d %d
    ",ansx,ansy);
    	}
    	return 0;
    }
    


  • 相关阅读:
    性能测试培训:性能瓶颈分析思路
    (国内)完美下载Android源码Ubuntu版
    (国内)完美下载android源代码(文章已经丢失)
    【翻译】Ext JS最新技巧——2015-10-21
    ubuntu 中 eclipse 的菜单栏 显示问题
    谷歌代码库已超过 20 亿行代码,他们是如何管理的?
    架构方面的资料集锦
    Android Studio 使用 Gradle 打包 Jar
    【翻译】Ext JS最新技巧——2015-8-11
    【翻译】在Ext JS 6通用应用程序中使用既共享又特定于视图的代码
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282789.html
Copyright © 2020-2023  润新知