OSDN Git Service

Update divide-combine.md
authorxyjg <50234881+xyjg@users.noreply.github.com>
Mon, 2 Sep 2019 11:45:54 +0000 (19:45 +0800)
committerGitHub <noreply@github.com>
Mon, 2 Sep 2019 11:45:54 +0000 (19:45 +0800)
docs/ds/divide-combine.md

index 4fc3b82..2286f22 100644 (file)
@@ -178,46 +178,12 @@ const int N = 200010;
 
 int n, m, a[N], st1[N], st2[N], tp1, tp2, rt;
 int L[N], R[N], M[N], id[N], cnt, typ[N], bin[20], st[N], tp;
-
-char gc() {
-  static char *p1, *p2, s[1000000];
-  if (p1 == p2) p2 = (p1 = s) + fread(s, 1, 1000000, stdin);
-  return (p1 == p2) ? EOF : *p1++;
-}
-int rd() {
-  int x = 0;
-  char c = gc();
-  while (c < '0' || c > '9') c = gc();
-  while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + c - '0', c = gc();
-  return x;
-}
-char ps[1000000], *pp = ps;
-void flush() {
-  fwrite(ps, 1, pp - ps, stdout);
-  pp = ps;
-}
-void push(char x) {
-  if (pp == ps + 1000000) flush();
-  *pp++ = x;
-}
-void write(int l, int r) {
-  static int sta[N], top;
-  if (!l)
-    push('0');
-  else {
-    while (l) sta[++top] = l % 10, l /= 10;
-    while (top) push(sta[top--] ^ '0');
-  }
-  push(' ');
-  if (!r)
-    push('0');
-  else {
-    while (r) sta[++top] = r % 10, r /= 10;
-    while (top) push(sta[top--] ^ '0');
-  }
-  push('\n');
-}
-
+//本篇代码原题应为 CERC2017 Intrinsic Interval
+//a数组即为原题中对应的排列
+//st1和st2分别两个单调栈,tp1、tp2为对应的栈顶,rt为析合树的根
+//L、R数组表示该析合树节点的左右端点,M数组的作用在析合树构造时有提到
+//id存储的是排列中某一位置对应的节点编号,typ用于标记析点还是合点
+//st为存储析合树节点编号的栈,tp为其栈顶 
 struct RMQ {  // 预处理 RMQ(Max & Min)
   int lg[N], mn[N][17], mx[N][17];
   void chkmn(int& x, int y) {
@@ -278,7 +244,7 @@ struct SEG {  // 线段树
       return query(ls, l, mid);
     else
       return query(rs, mid + 1, r);
-    // 如果不存在 0 的位置就会自动返回一个极大值
+    // 如果不存在 0 的位置就会自动返回当前你查询的位置 
   }
 } T;
 
@@ -289,7 +255,6 @@ struct Edge {
 void add(int u, int v) {  // 树结构加边
   E[o] = (Edge){v, hd[u]};
   hd[u] = o++;
-  // printf("%d %d\n",u,v);
 }
 void dfs(int u) {
   for (int i = 1; bin[i] <= dep[u]; ++i) fa[u][i] = fa[fa[u][i - 1]][i - 1];
@@ -348,7 +313,8 @@ void build() {
         R[st[tp]] = i, add(st[tp], now), now = st[tp--];
       } else if (judge(L[st[tp]], i)) {
         typ[++cnt] = 1;  // 合点一定是被这样建出来的
-        L[cnt] = L[st[tp]], R[cnt] = i, M[cnt] = L[now];
+        L[cnt] = L[st[tp]], R[cnt] = i, M[cnt] = L[now]; 
+        //这里M数组的作用是保证合点的儿子排列是单调的 
         add(cnt, st[tp--]), add(cnt, now);
         now = cnt;
       } else {
@@ -375,22 +341,26 @@ void query(int l, int r) {
   int z = lca(x, y);
   if (typ[z] & 1)
     l = L[go(x, dep[x] - dep[z] - 1)], r = R[go(y, dep[y] - dep[z] - 1)];
+    //合点这里特判的原因是因为这个合点不一定是最小的包含l,r的连续段.
+       //具体可以在上面的例图上试一下查询7,10 
   else
     l = L[z], r = R[z];
-  write(l, r);
+  printf("%d %d\n",l,r);
 }  // 分 lca 为析或和,这里把叶子看成析的
 
 int main() {
-  freopen("c.in", "r", stdin);
-  freopen("c.out", "w", stdout);
-  n = rd();
-  for (int i = 1; i <= n; ++i) a[i] = rd();
+  scanf("%d",&n);
+  for (int i = 1; i <= n; ++i) scanf("%d",&a[i]);
   D.build();
   build();
   dfs(rt);
-  m = rd();
-  for (int i = 1; i <= m; ++i) query(rd(), rd());
-  return flush(), 0;
+  scanf("%d",&m);
+  for (int i = 1; i <= m; ++i) {
+       int x,y;
+       scanf("%d%d",&x,&y);
+       query(x,y);
+  }
+  return  0;
 }
 // 20190612
 // 析合树