zoukankan      html  css  js  c++  java
  • JZOJ6368. 【NOIP2019模拟2019.9.25】质树(tree)

    Description

    大神 wyp 手里有棵二叉树,每个点有一个点权。大神 wyp 的这棵树是质树,因为
    随便找两个不同的点 u, v,只要 u 是 v 的祖先,都满足 u 和 v 的点权互质。
    现在你通过偷看了解到了大神 wyp 这棵树的中序遍历的点权值,你想复原出大神
    wyp 的树,或者指出不可能。
    n<=1e6

    Solution

    • 每一次取一个区间中的与其他位置互质的位置为根,如果有多个显然都可以。
    • 只用预处理左边右边第一个与它不互质的就可以O(1)判。
    • 如果直接暴力找每个点的话是n2的。
    • 我们只要从两边搜同时搜这个互质的位置就好了。
    • T(n)=T(x)+T(n-x)+min(x,n-x)
    • 跟dsu on tree (一种启发式合并)的时间是类似的。
    • 每个点最多贡献log。
    • O(n log n)
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define maxn 1000005
    #define maxm 10000005
    using namespace std;
    
    int n,i,j,k,x,a[maxn],f[maxn],L[maxn],R[maxn];
    int bz[maxm],tot,pri[maxm],g[maxm],nx[maxm];
    
    void read(int &x){
    	x=0; char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar());
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    }
    
    void Get_Prime(){
    	for(int i=2;i<maxm;i++) {
    		if (!bz[i]) {pri[++tot]=i;g[i]=i;}
    		for(int j=1;j<=tot&&i*pri[j]<maxm;j++) {
    			bz[i*pri[j]]=1;
    			g[i*pri[j]]=pri[j];
    			if (i%pri[j]==0) break;
    		}
    	}
    }
    
    int pd(int l,int r,int x){
    	return L[x]<l&&R[x]>r;
    }
    
    void Solve(int l,int r,int x){
    	if (l==r) f[l]=x;
    	if (l>r) return;
    	for(int len=0;len<=(r-l+1)/2;len++){
    		int i=l+len,j=r-len;
    		if (pd(l,r,i)){
    			Solve(l,i-1,i);
    			Solve(i+1,r,i);
    			f[i]=x; return;
    		}
    		if (pd(l,r,j)){
    			Solve(l,j-1,j);
    			Solve(j+1,r,j);
    			f[j]=x; return;
    		}
    	}
    	printf("impossible");
    	exit(0);
    }
    
    int main(){
    	freopen("tree.in","r",stdin);
    	freopen("tree.out","w",stdout);	
    	Get_Prime();
    	read(n); 
    	for(i=1;i<=n;i++) read(a[i]);
    	for(i=1;i<=n;i++) {
    		L[i]=0,x=a[i];
    		while (x>1){
    			if (nx[g[x]]!=i) L[i]=max(L[i],nx[g[x]]);
    			nx[g[x]]=i,x/=g[x];
    		}
    	}
    	memset(nx,0,sizeof(nx));
    	for(i=n;i>=1;i--) {
    		R[i]=n+1,x=a[i];
    		while (x>1){
    			if (nx[g[x]]!=i&&nx[g[x]]) R[i]=min(R[i],nx[g[x]]);
    			nx[g[x]]=i,x/=g[x];
    		}
    	}
    	Solve(1,n,0);
    	for(i=1;i<=n;i++) printf("%d ",f[i]);
    }
    
  • 相关阅读:
    索引唯一性扫描(INDEX UNIQUE SCAN)
    索引范围扫描(INDEX RANGE SCAN)
    算法设计与分析——回溯法算法模板
    操作系统考试复习大纲
    windows cmd 生成文件目录树
    Java 匿名类和lambda表达式
    下载Abook 高等教育出版社网站资料
    操作系统——银行家算法(Banker's Algorithm)
    算法设计与分析——最大团问题(回溯法)
    JVM内存区域
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090951.html
Copyright © 2011-2022 走看看