【启发式拆分】bzoj5200: [NWERC2017]Factor-Free Tree

和bzoj4059: [Cerc2012]Non-boring sequences非常相似

Description

一棵Factor-Free Tree是指一棵有根二叉树,每个点包含一个正整数权值,且每个点的权值都与其所有祖先的权值互质。
二叉树中序遍历是指按照左子树-根-右子树的顺序递归遍历二叉树,将每个点的权值依次写下来得到的序列。
给定一个序列a_1,a_2,...,a_n,请判断它是不是可能是某棵Factor-Free Tree的中序遍历序列,如果是的话请给出例子。

Input

第一行包含一个正整数n(1<=n<=1000000)。
第二行包含n个正整数a_1,a_2,...,a_n(1<=a_i<=10^7),表示节点编号为1到n的每个点的权值。

Output

若不是,输出impossible
否则输出一行n个整数,依次表示序列每一项代表的节点在树中的父亲节点,若是根节点则输出0。
若有多组解,输出任意一组。

题目分析

暴力做法就是在$[l,r]$内找到一个$rt$满足$\forall (a[rt],a[i])=1 \, rt≠i$,并递归做下去。这样复杂度是$O(n^3)$的。

考虑如何利用重复信息。互质看上去不好处理,但其实不过是一种二元关系而已。那么固定一个量,即处理出对于$a_i$,与其互质的数的最大区间$[l,r]$。

转成这一步,就可以用bz4059的“启发式拆分”方法去做了。

总结一下:“启发式拆分”这种方法适用于一类可拆分的连续的区间问题。“可拆分”是指只需要在区间内寻找一个断点,并且拆分之后就不会再次合并;“连续”意味着对于固定的$i$,它所能影响到的区间是连续的,即非法之后不会再次合法。

不要忘记左右横跳。

 1 #include<bits/stdc++.h>
 2 #define REG register int
 3 const int maxn = 1000035;
 4 const int maxNum = 10000035;
 5 
 6 int n,mx,a[maxn],fa[maxn];
 7 int pr[maxn],res[maxNum],pre[maxn],nxt[maxn],lst[maxNum];
 8 std::bitset<maxNum> vis;
 9 
10 inline char nc(){
11   static char buf[100000],*p1=buf,*p2=buf;
12   return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
13 }
14 #define getchar nc
15 int read()
16 {
17     char ch = getchar();
18     int num = 0, fl = 1;
19     for (; !isdigit(ch); ch=getchar())
20         if (ch=='-') fl = -1;
21     for (; isdigit(ch); ch=getchar())
22         num = (num<<1)+(num<<3)+ch-48;
23     return num*fl;
24 }
25 void write(int x){if (x/10) write(x/10);putchar(x%10+'0');}
26 void makePrime(int Top)
27 {
28     for (int i=2; i<=Top; i++)
29     {
30         if (!vis[i]) res[i] = i, pr[++pr[0]] = i;
31         for (int j=1; j<=pr[0]&&1ll*pr[j]*i<=Top; j++)
32         {
33             vis[i*pr[j]] = 1, res[i*pr[j]] = pr[j];
34             if (i%pr[j]==0) break;
35         }
36     }
37 }
38 bool merge(int l, int r, int fat)
39 {
40     if (l > r) return 1;
41     int L = l, R = r;
42     while (L <= R)
43     {
44         if (pre[L] < l&&nxt[L] > r){
45             fa[L] = fat;
46             return merge(l, L-1, L)&&merge(L+1, r, L);
47         }
48         if (pre[R] < l&&nxt[R] > r){
49             fa[R] = fat;
50             return merge(l, R-1, R)&&merge(R+1, r, R);
51         }
52         L++, R--;
53     }
54     return 0;
55 }
56 int main()
57 {
58     n = read();
59     for (REG i=1; i<=n; i++) a[i] = read(), mx = a[i]>mx?a[i]:mx;
60     makePrime(mx);
61     for (REG i=1; i<=n; i++)
62     {
63         REG num = a[i], tmp = 0, div;
64         while (num!=1)
65         {
66             div = res[num];
67             if (lst[div] > tmp) tmp = lst[div];
68             lst[div] = i;
69             while (num%div==0) num /= div;
70         }
71         pre[i] = tmp;
72     }
73     for (REG i=1; i<=mx; i++) lst[i] = n+1;
74     for (REG i=n; i; i--)
75     {
76         REG num = a[i], tmp = n+1, div;
77         while (num!=1)
78         {
79             div = res[num];
80             if (lst[div] < tmp) tmp = lst[div];
81             lst[div] = i;
82             while (num%div==0) num /= div;
83         }
84         nxt[i] = tmp;
85     }
86     if (merge(1, n, 0)){
87         for (REG i=1; i<=n; i++)
88             write(fa[i]), putchar(i!=n?' ':'\n');
89     }else puts("impossible");
90     return 0;
91 }

 

 

END

posted @ 2018-11-07 15:28  AntiQuality  阅读(582)  评论(0编辑  收藏  举报