[bzoj4765]普通计算姬——分块
Brief Description
给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权
值和。支持下列两种操作:
1 给定两个整数u,v,修改点u的权值为v。
2 给定两个整数l,r,计算sum[l]+sum[l+1]+....+sum[r-1]+sum[r]
Algorithm Design
我们考察暴力算法:
对于查询,我们如果处理出所有的sum[i]就可以处理了。考虑到是树上的子树查询,我们考虑使用dfs序,使用BIT维护即可,这个算法是\(\Theta(log n)\)的。
对于修改,如果我们能够记录每个点是否可以被这个修改的点影响,我们就可以扫一遍就ok了。这样的复杂度是\(\Theta(nlogn)\)的。
我们可以看到修改的复杂度比较大,我们考虑使用分块平衡一下这两个算法,假设我们\(h(n)\)分一块,
对于查询,我们可以把查询区间分为\(\Theta(\frac{n}{h(n)})\)个区间,对于每个区间直接统计,对于两边的区间直接统计复杂度\(\Theta(h(n)log(h(n))\)
对于修改,我们统计每一个区域会被修改的点修改几次,直接统计影响即可。复杂度是\(\Theta(\frac{n}{h(n)})\)
这样,算法总的复杂度就是\(\Theta(h(n)log(h(n))+\frac{n}{h(n)})\),为了方便,我们设\(h(n) = \sqrt n\)。
Code
#include <cmath>
#include <cstdio>
#define ll unsigned long long
const ll maxn = 100010;
const ll maxm = 320;
ll value[maxn], bit[maxn << 1], wtf[maxn];
int f[maxn][maxm];
int t[maxm], l[maxn], r[maxn], head[maxn], b[maxn];
ll n, m, rt, ind = 0, cnt = 0, blockm, block;
struct edge {
  ll to, next;
} e[maxn << 2];
ll lowbit(ll x) { return x & -x; }
void change(ll pos, ll x) {
  for (ll i = pos; i <= n; i += lowbit(i))
    bit[i] += x;
}
ll sum(ll pos) {
  ll ans = 0;
  for (ll i = pos; i > 0; i -= lowbit(i))
    ans += bit[i];
  return ans;
}
void insert(ll x, ll y) {
  e[++cnt].to = y;
  e[cnt].next = head[x];
  head[x] = cnt;
  e[++cnt].to = x;
  e[cnt].next = head[y];
  head[y] = cnt;
}
void dfs(ll x, ll fa) {
  t[b[x]]++;
  for (ll i = 1; i <= blockm; i++)
    f[x][i] = t[i];
  l[x] = ++ind;
  change(l[x], value[x]);
  for (ll i = head[x]; i; i = e[i].next) {
    if (e[i].to != fa)
      dfs(e[i].to, x);
  }
  r[x] = ind;
  t[b[x]]--;
}
int main() {
#ifndef ONLINE_JUDGE
  freopen("input", "r", stdin);
#endif
  scanf("%llu %llu", &n, &m);
  block = (int)sqrt(n);
  blockm = (n - 1) / block + 1;
  for (ll i = 1; i <= n; i++) {
    scanf("%llu", &value[i]);
  }
  for (ll i = 1; i <= n; i++)
    b[i] = (i - 1) / block + 1;
  for (ll i = 1; i <= n; i++) {
    ll u, v;
    scanf("%llu %llu", &u, &v);
    if (u == 0)
      rt = v;
    else
      insert(u, v);
  }
  dfs(rt, 0);
  for (ll i = 1; i <= n; i++)
    wtf[b[i]] += sum(r[i]) - sum(l[i] - 1);
  for (ll i = 1; i <= m; i++) {
    ll op, u, v;
    scanf("%llu %llu %llu", &op, &u, &v);
    if (op == 1) {
      change(l[u], v - value[u]);
      for (ll j = 1; j <= blockm; j++)
        wtf[j] += 1ll * f[u][j] * (v - value[u]);
      value[u] = v;
    } else {
      ll ans = 0;
      if (b[u] == b[v])
        for (ll j = u; j <= v; j++)
          ans += sum(r[j]) - sum(l[j] - 1);
      else {
        for (ll j = b[u] + 1; j <= b[v] - 1; j++)
          ans += wtf[j];
        for (ll j = u; b[j] == b[u] && j <= n; j++)
          ans += sum(r[j]) - sum(l[j] - 1);
        for (ll j = v; b[j] == b[v] && j; j--)
          ans += sum(r[j]) - sum(l[j] - 1);
      }
      printf("%llu\n", ans);
    }
  }
}
[bzoj4765]普通计算姬——分块的更多相关文章
- [BZOJ4765]普通计算姬(分块+树状数组)
		4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 1725 Solved: 376[Submit][Status][Discus ... 
- BZOJ4765: 普通计算姬
		BZOJ4765: 普通计算姬 题目描述 传送门 题目分析 求的和非常奇怪,不具有连续性,所有上树的数据结构全死了. 考虑分块,思考对于一段连续的询问区间可以直接询问整块,零散块可以在树上dfs序暴力 ... 
- 2018.06.30 BZOJ4765: 普通计算姬(dfs序+分块+树状数组)
		4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MB Description "奋战三星期,造台计算机".小G响应号召,花了三小时 ... 
- [bzoj4765]普通计算姬(分块+树状数组+DFS序)
		题意 给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权值和.计算姬支持下列两种操作: 1 给定两个整数u,v,修改点u的权值为v. 2 ... 
- BZOJ 4765 普通计算姬 (分块 + BIT)
		4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 1547 Solved: 329[Submit][Status][Discus ... 
- BZOJ4765 普通计算姬(分块+树状数组)
		对节点按编号分块.设f[i][j]为修改j号点对第i块的影响,计算f[i][]时dfs一遍即可.记录每一整块的sum.修改时对每一块直接更新sum,同时用dfs序上的树状数组维护子树和.查询时累加整块 ... 
- bzoj4765: 普通计算姬 (分块 && BIT)
		最近一直在刷分块啊 似乎感觉分块和BIT是超级棒的搭档啊 这道题首先用dfs预处理一下 得到每一个sum值 此时查询是O(1)的 (前缀和乱搞什么的 但是修改需要O(n) (需要修改该节点所有祖先的 ... 
- BZOJ 4765: 普通计算姬 [分块 树状数组 DFS序]
		传送门 题意: 一棵树,支持单点修改和询问以$[l,r]$为根的子树的权值和的和 只有我这种不会分块的沙茶不会做这道题吗? 说一点总结: 子树和当然上$dfs$序了,询问原序列一段区间所有子树和,对原 ... 
- BZOJ 4765: 普通计算姬 (分块+树状数组)
		传送门 解题思路 树上的分块题,,对于修改操作,每次修改只会对他父亲到根这条链上的元素有影响:对于查询操作,每次查询[l,r]内所有元素的子树,所以就考虑dfn序,进标记一次,出标记一次,然后子树就是 ... 
随机推荐
- svn资源库url问题
			今天连接svn资源库的时候一直出现 RA layer request failedsvn: Unable to connect to a repository at URL http://... sv ... 
- linux学习总结-----web前端①
			<html> <head> <title></title> <meta charset='utf-8'/> ... </head> ... 
- LSTM调参经验
			0.开始训练之前先要做些什么? 在开始调参之前,需要确定方向,所谓方向就是确定了之后,在调参过程中不再更改 1.根据任务需求,结合数据,确定网络结构. 例如对于RNN而言,你的数据是变长还是非变长:输 ... 
- java编程思想 内容总结
			Java编程思想重点笔记(Java开发必看) Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面 试过程中,而且 ... 
- 测试理论- the conten of test plan
			1 testing objects 测试对象 2 testing scope 测试范围 3 testing the frame (?) 4 the environment 5 reason for t ... 
- Windows下LATEX排版论文攻略—CTeX、JabRef使用心得
			笔者刚刚接触到TEX排版,相关知识完全空白,用了两天时间学习并完成了一篇论文的完整排版. 期间遇到不少小问题,着实辛苦,分享至上,现将其解决办法总结归纳,共同学习. 一.工具介绍 TeX是一个很好排版 ... 
- C++ 中神奇的头文件,懒人专用
			今天在做题的时候,偶然发现了一种神奇头文件.他的使用方法以及内容如下: #include <bits/stdc++.h> // C++ includes used for precompi ... 
- pta函数作业
			7-10 设计思路:本题需要判断一个正整数数是否为素数,所谓素数,就是除一和本身外没有其他因数的数.具体判断过程如下:对于一个大于一的整数,从2开始用循环计数i去除此数,若余数不为零,则循环计数i自加 ... 
- HDU 1005 Wooden Sticks
			http://acm.hdu.edu.cn/showproblem.php?pid=1051 Problem Description There is a pile of n wooden stick ... 
- Citrix Netscaler负载均衡算法
			Citrix Netscaler负载均衡算法 http://blog.51cto.com/caojin/1926308 众所周知,作为新一代应用交付产品的Citrix Netscaler具有业内领先的 ... 
