Description

题目背景:
尊者神高达作为一个萌新,在升级路上死亡无数次后被一只大黄叽带回了师门。他加入师门后发现有无穷无尽的师兄弟姐妹,这几天新副本开了,尊者神高达的师门作为一个 pve师门,于是他们决定组织一起去开荒。

题目描述:
师门可以看做以 1 为根的一棵树,师门中的每一个人都有一定的装备分数。一共会有 q 个事件。每个事件可能是一次开荒,也可能是因为开荒出了好装备而导致一个人的装分出现了变化。对于一次开荒,会有 k 个人组织,由于师门的号召力很强,所以所有在组织者中任意两个人简单路径上的人都会参加。

Input

第一行 n ,q;
接下来 1 行 n 个数,代表每个人的分值;
接下来 n-1 行 u,v 代表一条边
接下来 q 行
Q 代表询问,接下来 k 个数代表组织的人数,读入为 0时停止读入。
C 代表修改,输入 x,w 代表将 x 的分值变为 w

Output

共 Q 的数量行,为开荒的人的总分值

Sample Input

4 4
10 5 2 2
1 2
2 3
2 4
Q 3 4 0
C 3 200
Q 3 4 0
Q 1 4 0

Sample Output

9
207
17样例解释:
第一次询问,参加的人有 2,3,4 5+2+2=9
第一次修改,权值为 10 5 200 2
第二次询问,参加的人有 2,3,4 5+200+2=207
第三次询问,参加的人有 1,2,4 10+5+2=17

Data Constraint

数据范围:
20%的数据 n<=10000,q<=500;
另外 20%的数据 k=2
另外 20%的数据 没有修改操作
所有数据 n,q<=100000,所有询问 k 的和<=1000000
保证数据合法

题解

  • 题目大意,有q次操作,询问操作是求k个点两两到lca所经过点的点权和,修改操作就是修改一个点的点权
  • 首先,求距离可以用树状数组按照dfs序加入,类似差分约束一样求
  • 当然修改也可以
  • 那么现在问题就是直接暴力两两lca做显然不行,要找一种更快的做法
  • 可以建一棵虚树
  • 然后对于虚树上的非父亲节点,直接求出他到父亲的点权和(不包括父亲),而对于父亲则直接加上自己的点权即可

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 using namespace std;
 6 const int N=2e5+10;
 7 int n,Q,tot,num,cnt,p,w,head[N],v[N],be[N],en[N],fa[N],d[N],dep[N],f[N][20],k[N],q[N];
 8 long long sz[N],ans;
 9 struct edge {int to,from;}e[N];
10 void dfs(int x,int pre)
11 {
12     f[x][0]=fa[x]=pre,be[x]=++tot,d[x]=d[fa[x]]+1,dep[x]=dep[pre]+1;
13     for (int i=head[x];i;i=e[i].from) if (e[i].to!=pre) dfs(e[i].to,x);
14     en[x]=tot;
15 }
16 bool cmp(int x,int y) { return be[x]<be[y]; }
17 int getlca(int x,int y)
18 {
19     if (dep[x]<dep[y]) swap(x,y);
20     for (int i=18;i>=0;i--) if (dep[f[x][i]]>=dep[y]) x=f[x][i];
21     if (x==y) return x;
22     for (int i=18;i>=0;i--) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
23     return f[x][0];
24 }
25 void add(int x,int y) { for (;x<=n;x+=x&-x) sz[x]+=y; }
26 long long getsum(int x)
27 {
28     long long v=0;
29     for (;x;x-=x&-x) v+=sz[x];
30     return v;
31 }
32 void insert(int x,int y) { e[++cnt].to=y; e[cnt].from=head[x]; head[x]=cnt; }
33 int main()
34 {
35     //freopen("kaihuang.in","r",stdin),freopen("kaihuang.out","w",stdout);
36     scanf("%d%d",&n,&Q);
37     for (int i=1;i<=n;i++) scanf("%d",&v[i]);
38     for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y),insert(y,x);
39     dfs(1,0);
40     for (int j=1;j<=19;j++) for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
41     for (int i=1;i<=n;i++) add(be[i],v[i]),add(en[i]+1,-v[i]);
42     while (Q--)
43     {
44         scanf("\n");
45         char ch=getchar(); int x,y;
46         if (ch=='C')
47         {
48             scanf("%d%d",&x,&y),y-=v[x],v[x]+=y;
49             add(be[x],y),add(en[x]+1,-y);
50         }
51         else
52         {
53             num=1,p=0; scanf("%d",&k[num]); while (k[num]!=0) scanf("%d",&k[++num]); num--;
54             sort(k+1,k+num+1,cmp);
55             w=num; for (int i=1;i<=w-1;i++) k[++num]=getlca(k[i],k[i+1]);
56             sort(k+1,k+num+1,cmp),num=unique(k+1,k+num+1)-k-1;
57             ans=0;
58             for (int i=1;i<=num;i++)
59             {
60                 for (;p&&en[q[p]]<be[k[i]];) p--;
61                 ans+=p?getsum(be[k[i]])-getsum(be[q[p]]):v[k[i]];
62                 q[++p]=k[i];
63             }
64             printf("%lld\n",ans);
65         }
66     }
67 }

转载于:https://www.cnblogs.com/Comfortable/p/9802591.html

[虚树][树状数组][lca] Jzoj P5908 开荒相关推荐

  1. jzoj4050-寻宝游戏【二分,树状数组,LCA】

    正题 题目链接:https://jzoj.net/senior/#contest/show/3017/1 题目大意 nnn个点的一棵树,mmm次操作,修改一个地方的宝藏. 每次操作后求拿完所以宝藏并回 ...

  2. 【BZOJ2819】Nim 树状数组+LCA

    [BZOJ2819]Nim Description 著名游戏设计师vfleaking,最近迷上了Nim.普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可 ...

  3. 牛客多校1 - Infinite Tree(虚树+换根dp+树状数组)

    题目链接:点击查看 题目大意:给出一个无穷个节点的树,对于每个大于 1 的点 i 来说,可以向点 i / minvid[ i ] 连边,这里的 mindiv[ x ] 表示的是 x 的最小质因数,现在 ...

  4. 【HDU - 6203】ping ping ping(lca+贪心思想,对lca排序,树状数组差分)

    题干: 给出一个n+1个点的树,以及p个点对,需要断开一些点,使得这p个点对路径不连通.输出应该断开的最少点数. 解题报告: 从那p个点对入手的话:首先考虑只有一对点的话,肯定是这条路径上的随便一个点 ...

  5. 「模拟赛20180306」回忆树 memory LCA+KMP+AC自动机+树状数组

    题目描述 回忆树是一棵树,树边上有小写字母. 一次回忆是这样的:你想起过往,触及心底--唔,不对,我们要说题目. 这题中我们认为回忆是这样的:给定 \(2\) 个点 \(u,v\) (\(u\) 可能 ...

  6. Codeforces Gym 101142 G Gangsters in Central City (lca+dfs序+树状数组+set)

    题意: 树的根节点为水源,编号为 1 .给定编号为 2, 3, 4, -, n 的点的父节点.已知只有叶子节点都是房子. 有 q 个操作,每个操作可以是下列两者之一: + v ,表示编号为 v 的房子 ...

  7. Housewife Wind POJ - 2763 倍增LCA+树状数组 或 树链剖分+线段树

    题目 链接:http://poj.org/problem?id=2763 Language:Default Housewife Wind Time Limit: 4000MS   Memory Lim ...

  8. HDU 6203 ping ping ping (在线倍增lca+DFS序+树状数组)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6203 #include<bits/stdc++.h> using namespace st ...

  9. HDU 6203 2017沈阳网络赛 LCA,DFS+树状数组

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6203 题意:n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组 U V ...

最新文章

  1. 9、Kubernetes控制器Controller详解
  2. 机器学习算法加强——数据清洗
  3. YOLOv3 《YOLOv3: An Incremental Improvement》论文笔记
  4. C++, C#, Java, VB.NET,到底该选择哪一门语言?
  5. C# 页面调用控制台应用程序
  6. jzoj3501-消息传递【换根法,树形dp】
  7. ZOJ.3551.Bloodsucker(期望DP)
  8. python将excel表按地方拆分_Python将一个Excel拆分为多个Excel
  9. 2020年中国互联网租车报告
  10. android学习笔记---36_Activity生命周期
  11. echarts中x轴文件消失_实测实例:labview中波形图X轴刻度任意刻度设置
  12. 小芭比linux怎么装win7_小户型再怎么装也是小?看完我闭嘴了
  13. python管道_python 多进程之管道实例(模板)
  14. 23. jQuery 遍历 - 过滤
  15. NGN学习笔记6——NGN的业务提供技术
  16. compositionAPI
  17. HTTPS的原理与具体实现过程及HTTP服务的虚拟目录简介
  18. html 图片查看 ie7,兼容ie6跟ie7 的16进制码流在html中显示为图片代码(base64)
  19. 今天起,上海用户可以用滴滴App免费打无人车了
  20. python实现淘宝毫秒级秒杀 自动付款

热门文章

  1. 英语采访问题之:你每天上班的动机是什么?
  2. 如何在AWS亚马逊云上运行Angular应用
  3. 太阳能计算机屏幕是什么材质,魅蓝E的屏幕怎么样?屏幕材质是什么?
  4. java中活锁和死锁的区别_死锁、活锁、饿死和阻塞的个人理解
  5. vue计算多列和_解决vue 表格table列求和的问题
  6. 同一目录下有大量文件会影响效率吗_到底是什么原因才导致 select * 效率低下的?
  7. 除留余数法构造哈希表_哈希表算法原理
  8. matlab 双音多频 接收端检测到的号码,信号语音论文,关于基于MATLAB的双音多频信号识别相关参考文献资料-免费论文范文...
  9. linux使用ntp时间同步
  10. linux进程管理fork,Linux -- 进程管理之 fork() 函数