HDU 6547 树链剖分

大意是一颗有根树,根节点为1,树上有两个操作,一个是对两个节点间的节点开根号,一个是询问两个节点间所有节点的权值和
开根号就是暴力对每个节点开根号(因为开根号能很快的接近1)
(树链剖分解决树上问题就是把它转化成线性表,然后再用一些数据结构维护一下就好了。所以说线性表的的增删查改才是重点)
ac代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace {
  template <typename T> inline void read(T &x) {
    x = 0; T f = 1;char s = getchar();
    for(; !isdigit(s); s = getchar()) if(s == '-') f = -1;
    for(;  isdigit(s); s = getchar()) x = (x << 3) + (x << 1) + (s ^ 48);
    x *= f;
  }
}
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define _for(n,m,i) for (register int i = (n); i < (m); ++i)
#define _rep(n,m,i) for (register int i = (n); i <= (m); ++i)
const int N = 1e5+5;
struct edge{
  int next, to;
}e[N*2];
struct Node{
  int sum, l, r, ls, rs;
}a[N*2];
int n, m, cnt, head[N], v[N], rt;
int f[N], d[N], size[N], son[N], rk[N], top[N], id[N];
void add(int u, int v) {
  e[++cnt].to = v;
  e[cnt].next = head[u];
  head[u] = cnt;
}
void dfs1(int x) {
  size[x] = 1, d[x] = d[f[x]] + 1;
  for(int v, i = head[x]; i; i = e[i].next) {
    if((v = e[i].to) != f[x]) {
      f[v] = x, dfs1(v); size[x] += size[v];
      if(size[son[x]] < size[v]) son[x] = v;
    }
  }
}
void dfs2(int x, int tp) {
  top[x] = tp, id[x] = ++cnt, rk[cnt] = x;
  if(son[x]) dfs2(son[x], tp);
  for(int v, i = head[x]; i; i = e[i].next) {
    if((v = e[i].to) != f[x] && v != son[x]) 
      dfs2(v, v);
  }
}
inline void pushup(int x) {
  a[x].sum = a[a[x].ls].sum + a[a[x].rs].sum;
}
void build(int l, int r, int x) {
  if(l == r) {
    a[x].sum = v[rk[l]], a[x].l = a[x].r = l;
    return ;
  }
  int mid = l + r >> 1;
  a[x].ls = cnt++, a[x].rs = cnt++;
  build(l, mid, a[x].ls);
  build(mid + 1, r, a[x].rs);
  a[x].l = l,a[x].r = r;
  pushup(x);
}
inline len(int x) {
  return a[x].r - a[x].l + 1;
}
void upd(int l ,int r, int x) {
  if(a[x].l >= l && a[x].r <= r && a[x].sum == len(x)) {
    return ;
  }
  if(a[x].l == a[x].r) {
    a[x].sum = sqrt(a[x].sum);
    return ;
  }
  int mid = a[x].l + a[x].r >> 1;
  if(mid >= l) upd(l, r, a[x].ls);
  if(mid <  r) upd(l, r, a[x].rs);
  pushup(x);
}
int qry(int l, int r, int x) {
  if(a[x].l >= l && a[x].r <= r) return a[x].sum;
  int mid = a[x].l + a[x].r >> 1, ret = 0;
  if(mid >= l) ret += qry(l, r, a[x].ls);
  if(mid <  r) ret += qry(l , r, a[x].rs);
  return ret;
}
inline int sum (int x, int y) {
  int ret = 0;
  while(top[x] != top[y]) {
    if(d[top[x]] < d[top[y]]) swap(x, y);
    ret += qry(id[top[x]], id[x], rt) ;
    x = f[top[x]];
  } 
  if(id[x] > id[y]) swap(x, y);
  return ret + qry(id[x], id[y], rt);
}
void upd(int x, int y) {
  while(top[x] != top[y]) {
    if(d[top[x]] < d[top[y]]) swap(x, y);
    upd(id[top[x]], id[x], rt);
    x = f[top[x]];
  }
  if(id[x] > id[y]) swap(x, y);
  upd(id[x], id[y], rt);
}
signed main() {
  scanf("%lld%lld", &n, &m);
  for(int i = 1; i <= n; i++) read(v[i]);
  for(int x, y, i = 1; i < n; i++) {
    read(x);read(y);
    add(x, y);add(y, x);
  }
  cnt = 0, dfs1(1);dfs2(1,1);
  cnt = 0, build(1,n,rt = cnt++);
  for(int x, y, op, i = 1; i <= m; i++) {
    read(op);read(x);read(y);
    if(op == 0) upd(x,y);
    else printf("%lld\n", sum(x, y));
  }
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值