树链剖分 bzoj2325 [ZJOI2011]道馆之战

Posted foreverpiano

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树链剖分 bzoj2325 [ZJOI2011]道馆之战相关的知识,希望对你有一定的参考价值。

http://www.lydsy.com/JudgeOnline/problem.php?id=2325

吐槽一下部分分数据不满足性质
我打了6k的暴力..

考虑一条链的情况
记录8个值
m[0/1][0/1]表示左边从哪里开始走 右边从哪里开始走(上面还是下面) 最多是多少
l[0/1] r[0/1]表示左边右边最多延伸多少 gss1的套路

然后大力树剖一发 小心各种细节
复杂度\(O(m \log n ^ 2)\)

#include<bits/stdc++.h>
#define int long long
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
  x = 0; char c = getchar(); bool f = 0;
  for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
  for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
  if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
  for(int i = 1; i <= n; i ++)
    cout << a[i] << " ";
  puts("");
}

#define P pair<int, int>
#define MP make_pair
#define mid (l + (r - l) / 2)
#define ls (rt << 1)
#define rs (rt << 1 | 1)
#define root 1, n, 1
const int N = 1e5 + 233;
const int inf = 1e8 + 233;
struct E {
  int nxt, from, to;
}e[N << 1];
int head[N], e_cnt = 0;
char str[233];

inline void add(int u, int v) {
  e[++ e_cnt] = (E) {head[u], u, v}; head[u] = e_cnt; 
}

inline int cp(int a, int b) {
  return a > b ? a : b;
}

int n, m;
struct seg {
  int m00, m10, m01, m11;
  int l0, l1;
  int r0, r1;
  inline void ovo(void) {
    printf("%d %d %d %d\n", m00, m10, m01, m11);
    printf("%d %d %d %d\n", l0, l1, r0, r1);
  }
  inline void clear(void) {
    m00 = m10 = m01 = m11 = l0 = l1 = r0 = r1 = 0;  
  }
};
seg operator + (seg a, seg b) {
  seg c;
  c.m00 = cp(a.m00 + b.m00, a.m01 + b.m10);
  c.m01 = cp(a.m00 + b.m01, a.m01 + b.m11);
  c.m10 = cp(a.m10 + b.m00, a.m11 + b.m10);
  c.m11 = cp(a.m10 + b.m01, a.m11 + b.m11);
  c.l0 = cp(a.l0, cp(a.m00 + b.l0, a.m01 + b.l1));
  c.l1 = cp(a.l1, cp(a.m10 + b.l0, a.m11 + b.l1));
  c.r0 = cp(b.r0, cp(a.r0 + b.m00, a.r1 + b.m10));
  c.r1 = cp(b.r1, cp(a.r0 + b.m01, a.r1 + b.m11));
  return c;
}
namespace se {
  seg tr[N << 2];
  
  inline seg nw(void) {
    if(str[1] == '#' && str[2] == '#')
      return (seg) {-inf, -inf, -inf, -inf, -inf, -inf, -inf, -inf};
    if(str[1] == '.' && str[2] == '#')
      return (seg) {1, -inf, -inf, -inf, 1, -inf, 1, -inf};
    if(str[1] == '#' && str[2] == '.')
      return (seg) {-inf, -inf, -inf, 1, -inf, 1, -inf, 1};
    else
      return (seg) {1, 2, 2, 1, 2, 2, 2, 2};
  }

  inline void upd(int l, int r, int rt, int L) {
    if(l == r) {
      tr[rt] = nw();
      return ;
    }
    if(L <= mid) upd(l, mid, ls, L);
    else upd(mid + 1, r, rs, L);
    tr[rt] = tr[ls] + tr[rs];
  }

  inline seg query(int l, int r, int rt, int L, int R) {
    if(L == l && r == R) {
      return tr[rt];
    }
    if(R <= mid) return query(l, mid, ls, L, R);
    else if(L > mid) return query(mid + 1, r, rs, L, R);
    else return query(l, mid, ls, L, mid) + query(mid + 1, r, rs, mid + 1, R);
  }

  inline void debug(int l, int r, int rt) {
    cout << l << " " << r << "\n";
    tr[rt].ovo();
    if(l == r) 
      return ;
    debug(l, mid, ls);
    debug(mid + 1, r, rs);
  }
}
int dep[N], sz[N], fa[N], son[N], idx_cnt = 0, idx[N], top[N];
inline void dfs(int u, int fat) {
  dep[u] = dep[fat] + 1;
  sz[u] = 1; fa[u] = fat;
  for(int i = head[u]; i; i = e[i].nxt) {
    int v = e[i].to;
    if(v != fat) {
      dfs(v, u);
      sz[u] += sz[v];
      if(!son[u] || sz[son[u]] < sz[v])
        son[u] = v;
    }
  }
}

inline void frt(int u, int tp) {
  top[u] = tp; idx[u] = ++ idx_cnt;
  if(son[u]) frt(son[u], tp);
  for(int i = head[u]; i; i = e[i].nxt) {
    int v = e[i].to;
    if(v != fa[u] && v != son[u])
      frt(v, v);
  }
}

inline int L(seg &s) {
  return cp(0, cp(s.l0, s.l1));
}

inline int R(seg &s) {
  return cp(0, cp(s.r0, s.r1));
}

inline int Ans(seg &s) {
  return cp(0, cp(cp(s.m00, s.m01), cp(s.m10, s.m11)));
}

inline seg rev(seg a) {
  return (seg) {a.m00, a.m01, a.m10, a.m11, a.r0, a.r1, a.l0, a.l1};    
}

inline int query(int u, int v) {
  seg res1, res2;
  res1.clear(); res2.clear();
  while(top[u] != top[v]) {
    // go v
    if(dep[top[u]] < dep[top[v]]) {
      seg now = se::query(root, idx[top[v]], idx[v]);
      res2 = now + res2;
      v = fa[top[v]];
    }
    // go u
    else {
      seg now = se::query(root, idx[top[u]], idx[u]);
      res1 = now + res1;
      u = fa[top[u]];
    }
  }
  if(dep[u] < dep[v]) {
    seg now = se::query(root, idx[u], idx[v]);
    res2 = now + res2;  
  }
  else {
    seg now = se::query(root, idx[v], idx[u]);
    res1 = now + res1;
  }
  res1 = rev(res1) + res2;  
  return L(res1);
  
}

main(void) {
  read(n); read(m);
  for(int i = 1; i <= n - 1; i ++) {
    int x, y; read(x); read(y);
    add(x, y); add(y, x);
  }
  dfs(1, 0); frt(1, 1);
  for(int i = 1; i <= n; i ++) {
    scanf("%s", str + 1);
    se::upd(root, idx[i]);
  }
  for(int i = 1; i <= m; i ++) {
    scanf("%s", str + 1);
    if(str[1] == 'Q') {
      int l, r;
      read(l); read(r);
      cout << query(l, r) << "\n";
    }
    else {
      int id;
      read(id); scanf("%s", str + 1);
      se::upd(root, idx[id]);
    }
  }
}

以上是关于树链剖分 bzoj2325 [ZJOI2011]道馆之战的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2325 [ZJOI2011]道馆之战 树链剖分+DP+类线段树最大字段和

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

BZOJ 1036ZJOI 2008树的统计 树链剖分模板题

bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

BZOJ1036: [ZJOI2008]树的统计Count - 树链剖分 -

BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]