题目大意:

给定一棵\(n\)个节点的带权树有根树,设\(sum_p\)表示以点\(p\)为根的这棵子树中所有节点的权

计算姬支持下列两种操作:

  1. 给定两个整数\(u,v\),修改点\(u\)的权值为\(v\)。
  2. 给定两个整数\(l,r\),计算\(\sum_{i=l}^rsum_i\)

题解:

表示自己没能想出来...被同桌嘲讽了QAQ...

首先是这道题的数据范围很奇怪,只有10W,这就说明了你有充足的时间来瞎搞

所以我们就瞎搞

如果没有修改操作那么我们直接\(O(n)\)预处理就可以\(O(1)\)询问了

但是我们存在修改操作,而且一次修改朴素是\(O(n)\)的

但是我们发现:无论我们要修改多少个数的值,修改的复杂度总是\(O(n)\)的

所以我们多攒几次修改在外部维护其对答案的影响,然后凑够了再一块改.

所以我们考虑如何外部维护.

首先我们将问题放到树的dfs序上,

我们发现:

这个问题实际上就是让我们统计一下当前询问的sum区间中有多少区间覆盖了我们修改的点

(注意,每一个sum实际上都代表了dfs序中的一个区间)

所以我们可以一次枚举每一个点,求一下当前的sum区间中有多少区间覆盖了当前枚举的点.

对于这个操作我们可以直接用可持久化线段树瞎搞一下就好了

经过本人的测试:在随机数据下,积累68个修改操作的时候进行修改,跑得最快 !

本题还有一个大坑点 : 答案会炸long long需要开unsigned long long 才能过...

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline void read(ll &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 100010;
const int lim = 68;
struct Node{
Node *ch[2];
ll lazy;
}mem[maxn*50],*it,*null,*root[maxn];
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null;
null->lazy = 0;root[0] = null;
}
Node* insert(Node *rt,int l,int r,int L,int R){
Node *p = it++;*p = *rt;
if(L <= l && r <= R){
p->lazy ++;
return p;
}
int mid = l+r >> 1;
if(L <= mid) p->ch[0] = insert(p->ch[0],l,mid,L,R);
if(R > mid) p->ch[1] = insert(p->ch[1],mid+1,r,L,R);
return p;
}
ll query(Node *p,int l,int r,int pos){
if(l == r) return p->lazy;
int mid = l+r >> 1;
if(pos <= mid) return query(p->ch[0],l,mid,pos) + p->lazy;
else return query(p->ch[1],mid+1,r,pos) + p->lazy;
}
struct Edge{
int to,next;
}G[maxn<<1];
int head[maxn],cnt;
inline void add(int u,int v){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
}
ll c[maxn],ind[maxn],dfs_clock,oud[maxn];
#define v G[i].to
void dfs(int u,int f){
ind[u] = ++ dfs_clock;
for(int i = head[u];i;i=G[i].next){
if(v == f) continue;
dfs(v,u);
}oud[u] = dfs_clock;
}
#undef v
struct save{
ll bef,id,val;
save(){}
save(const ll &a,const ll &b,const ll &c){
bef = a;id = b;val = c;
}
}q[maxn];
int q_siz,n;
ull a[maxn],sum[maxn];
inline void rebuild(){
q_siz = 0;
memset(a,0,sizeof a);
for(int i=1;i<=n;++i){
a[ind[i]] += c[i];
}
for(int i=1;i<=n;++i) a[i] += a[i-1];
for(int i=1;i<=n;++i){
sum[i] = sum[i-1] + a[oud[i]] - a[ind[i]-1];
}
}
int main(){
init();
int m;read(n);read(m);
for(int i=1;i<=n;++i) read(c[i]);
int rt = 0;
for(int i=1,u,v;i<=n;++i){
read(u);read(v);
if(u == 0) rt = v;
else add(u,v),add(v,u);
}dfs(rt,0);
for(int i=1;i<=n;++i){
root[i] = insert(root[i-1],1,n,ind[i],oud[i]);
}
rebuild();
ll op,u,v;
while(m--){
read(op);read(u);read(v);
if(op == 1){
q[++q_siz] = save(c[u],u,v);
c[u] = v;
if(q_siz == lim) rebuild();
}else{
ll l = u,r = v;
ull ans = sum[v] - sum[u-1];
for(ll i=1;i<=q_siz;++i){
if(q[i].val - q[i].bef > 0) ans += 1ULL*(q[i].val - q[i].bef)*(query(root[r],1,n,ind[q[i].id]) - query(root[l-1],1,n,ind[q[i].id]));
if(q[i].val - q[i].bef < 0) ans -= 1ULL*(q[i].bef - q[i].val)*(query(root[r],1,n,ind[q[i].id]) - query(root[l-1],1,n,ind[q[i].id]));
}
printf("%llu\n",ans);
}
}
getchar();getchar();
return 0;
}

bzoj 4765: 普通计算姬 主席树+替罪羊树思想的更多相关文章

  1. BZOJ 4765 普通计算姬 dfs序+分块+树状数组+好题!!!

    真是道好题...感到灵魂的升华... 按dfs序建树状数组,拿前缀和去求解散块: 按点的标号分块,分成一个个区间,记录区间子树和 的 总和... 具体地,需要记录每个点u修改后,对每一个块i的贡献,记 ...

  2. BZOJ 4765 普通计算姬 (分块 + BIT)

    4765: 普通计算姬 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 1547  Solved: 329[Submit][Status][Discus ...

  3. bzoj 4765 普通计算姬(树状数组 + 分块)

    http://www.lydsy.com/JudgeOnline/problem.php?id=4765 很nice的一道题啊(可能是因为卡了n久终于做出来了 题意就是给你一棵带点权的有根树,sum( ...

  4. bzoj 4765: 普通计算姬

    Description "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些 .普通计算机能计算数列区间和,而普通计算姬能计算树中 ...

  5. bzoj 4765 普通计算姬 dfs序 + 分块

    题目链接 Description "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些.普通计算机能计算数列区间和,而普通计算姬能 ...

  6. BZOJ 4765: 普通计算姬 [分块 树状数组 DFS序]

    传送门 题意: 一棵树,支持单点修改和询问以$[l,r]$为根的子树的权值和的和 只有我这种不会分块的沙茶不会做这道题吗? 说一点总结: 子树和当然上$dfs$序了,询问原序列一段区间所有子树和,对原 ...

  7. BZOJ 4765: 普通计算姬 (分块+树状数组)

    传送门 解题思路 树上的分块题,,对于修改操作,每次修改只会对他父亲到根这条链上的元素有影响:对于查询操作,每次查询[l,r]内所有元素的子树,所以就考虑dfn序,进标记一次,出标记一次,然后子树就是 ...

  8. bzoj 4766: 文艺计算姬 -- 快速乘

    4766: 文艺计算姬 Time Limit: 1 Sec  Memory Limit: 128 MB Description "奋战三星期,造台计算机".小W响应号召,花了三星期 ...

  9. BZOJ 4766: 文艺计算姬

    4766: 文艺计算姬 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 456  Solved: 239[Submit][Status][Discuss] ...

随机推荐

  1. poj2816

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 29799   Accepted: 12090 De ...

  2. 如何基于EasyDSS体系的全套SDK完成各种场景下的视频应用需求

    需求背景 回顾EasyDSS的发展过程,基本上保持的是先局部后系统.先组件后平台的发展方式,一步一步夯实每一个细节功能点,从最基础.最兼容的音视频数据的拉流获取,到高效的.全兼容的数据推流,再到流媒体 ...

  3. 大数据学习系列(7)-- hadoop集群搭建

    1.配置ssh免登陆 #进入到我的home目录 cd ~/.ssh ssh-keygen -t rsa 执行完这个命令后,会生成两个文件id_rsa(私钥).id_rsa.pub(公钥) 将公钥拷贝到 ...

  4. Dajngo admin使用

    Dajngo admin使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.你可以在项目的 settings.py 中的 INS ...

  5. 网络的分层协议总结(转发:https://www.cnblogs.com/Zhang-wj/p/5907534.html)

    网络的分层协议总结 OSI七层模型OSI 中的层            功能                                                        TCP/IP ...

  6. R语言读取Excel文档

    在R语言数据管理(三):数据读写一博文中,我曾写到有关读取xls.xlsx文件时一般将文档改成csv文件读取,这是一般做法.csv文件也有其缺点,修改较为麻烦,当文件数据较大时尤为明显.而生活中必不可 ...

  7. SQL优化小结

    一 背景      客户数据库经常出现死锁.超时.查询慢等问题,数据库mssql,数据量主要表大概上千W. 二 收集信息      首先是要找出IO大.查询慢.使用频率高的脚本.直接用Profiler ...

  8. Git——基本思想和工作原理(二)

    核心知识点: 1.Git关注文件数据的整体是否发生变化,对更新的文件做一个快照,然后保存一个指向快照的索引,而不会关注文件数据的具体变化. 2.Git版本的更新几乎都发生在本地,不会因为没有网络而不能 ...

  9. Html标签使用——文字、列表、表格、超链接

    注:文章来源于传智播客毕向东老师使用课件和网络.整理学习如下: 一.Html内容 1.   Html就是超文本标记语言的简写,是最基础的网页语言. 2.   Html是通过标签来定义的语言,代码都是由 ...

  10. python 3 json 序列化

    python 3 json 序列化 我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特 ...