Unverified Commit 68e69c00 authored by xyjg's avatar xyjg Committed by GitHub
Browse files

Update divide-combine.md

parent 9e533452
Loading
Loading
Loading
Loading
+21 −51
Original line number Diff line number Diff line
@@ -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];
@@ -349,6 +314,7 @@ void build() {
      } else if (judge(L[st[tp]], i)) {
        typ[++cnt] = 1;  // 合点一定是被这样建出来的
        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
// 析合树