题目链接:点击查看

题目大意:给出一棵树,再给出 m 次操作,每次操作分为三种类型,dist( x , y ) 代表点 x 和点 y 之间的距离:

  1. 1 pos val:将点 pos 位置的值增加 val ,将其余所有点 x 的值,增加 val - dist( pos , x )
  2. 2 pos:点 pos 位置的值与 0 取 min
  3. 3 pos:查询点 pos 位置的值

题目分析:参考博客:https://blog.csdn.net/tianyizhicheng/article/details/107734665

第二个操作显然是充数的,额外用一个 delta 数组随便维护一下就好了,主要是操作 1 和操作 3

对于每次操作 1 来说,肯定不能暴力去维护所有的 n 个点,所以我们不妨将点权转换为每个点与 root 节点( 设为点 1 )的相对权值

画个图然后分类讨论一下吧,现在假设我们将点 6 的权值增加 w,那么显然根节点(点1)的权值会增加 w - 2 ,我们将点 1 的权值记为 all ,此时也就是 all = w - 2,因为点 6 的深度为 2

如果我们想要求与点 6 的 lca 为 root 的点的权值,也就是点 1 , 2 , 3 , 4 的权值,显然 all - deep[ x ] 就是答案了,因为 lca 为 1 ,所以这些点与点 1 的距离增大,相应的与点 6 的距离也会增大,答案自然也会变小

既然我们想让答案与 deep 形成关系,对于那些,与点 6 的 lca 不为 root 的点,如:点 5 , 6 , 7 ,也需要构造一个公式,也就是 all - deep[ x ] + y 为点 x 的权值,通过观察不难发现,这个 y 值可以分两种情况讨论:

  1. 当点 x 位于 点 1 ~ 点 6 的路径上,即点 5 和 6 ,那么 y 的值为点 1 ~ 点 x 的边数 * 2
  2. 否则,y 的值为点 1 ~ 点 6 的边数 * 2

综上所述,对于操作 1 来说,需要执行的操作就是:

  1. all += w - deep[ x ]
  2. 将点 1 ~ 点 x 这条路径上的边权 + 2

对于操作 3 查询来说,答案就是 all + ( 点 1 ~ 点 x 这条边上的边权之和 ) - deep[ x ] * num

注意,这里的 deep 为什么突然乘以 num 了,解释一下这个突然出现的 num ,其意义是操作 1 的数量,举个很简单的例子,还是上图,如果对点 6 进行两次操作 1 ,增加的权值都是 w ,那么此时的 all = ( w -  2 ) * 2 ,如果要求点 2 的权值,答案应该是 all - deep[ 2 ] * 2 而不是 all - deep[ 2 ]

剩下的就是实现了,对于树上路径的区间更改和区间查询,可以利用树链剖分和线段树来执行,因为是要对边权操作,所以可以将边权转换为点权,很基本的操作,直接实现就好了

操作 2 的 delta 就不多说了,如果操作 1 明白了的话,操作 2 看一眼代码应该就会了

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=5e4+100;LL all,tot,delta[N];vector<int>node[N];int deep[N],fa[N],son[N],num[N];void dfs1(int u,int f,int dep)
{deep[u]=dep;son[u]=-1;num[u]=1;fa[u]=f;for(auto v:node[u]){if(v==f)continue;dfs1(v,u,dep+1);num[u]+=num[v];if(son[u]==-1||num[son[u]]<num[v])son[u]=v;}
}int id[N],idd[N],top[N],cnt;//id[节点]=编号 idd[编号]=节点 void dfs2(int u,int f,int root)
{top[u]=root;id[u]=++cnt;idd[cnt]=u;if(son[u]!=-1)dfs2(son[u],u,root);for(auto v:node[u]){if(v==f||v==son[u])continue;dfs2(v,u,v);}
}struct Node
{int l,r;LL lazy,sum;LL mid(){return l+r>>1;}LL cal_len(){return r-l+1;}
}tree[N<<2];void pushup(int k)
{tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}void pushdown(int k)
{LL lz=tree[k].lazy;tree[k<<1].sum+=tree[k<<1].cal_len()*lz;tree[k<<1|1].sum+=tree[k<<1|1].cal_len()*lz;tree[k<<1].lazy+=lz;tree[k<<1|1].lazy+=lz;tree[k].lazy=0;
}void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;tree[k].sum=tree[k].lazy=0;if(l==r)return;int mid=tree[k].mid();build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}void update(int k,int l,int r)
{if(l>r)return;if(tree[k].r<l||tree[k].l>r)return;if(tree[k].l>=l&&tree[k].r<=r){tree[k].lazy+=2;tree[k].sum+=tree[k].cal_len()*2;return;}if(tree[k].lazy)pushdown(k);update(k<<1,l,r);update(k<<1|1,l,r);pushup(k);
}LL query(int k,int l,int r)
{if(l>r)return 0;if(tree[k].r<l||tree[k].l>r)return 0;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].sum;if(tree[k].lazy)pushdown(k);return query(k<<1,l,r)+query(k<<1|1,l,r);
}void change(int x)
{while(top[x]!=1){update(1,id[top[x]],id[x]);x=fa[top[x]];}update(1,id[1]+1,id[x]);
}LL ask(int x)
{LL ans=0;while(top[x]!=1){ans+=query(1,id[top[x]],id[x]);x=fa[top[x]];}ans+=query(1,id[1]+1,id[x]);return ans;
}void init(int n)
{for(int i=0;i<=n;i++){delta[i]=0;node[i].clear();}cnt=tot=all=0;
}int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int w;cin>>w;while(w--){int n,m;scanf("%d%d",&n,&m);init(n);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);node[u].push_back(v);node[v].push_back(u);}dfs1(1,0,0);dfs2(1,0,1);build(1,1,n);while(m--){int op;scanf("%d",&op);if(op==1){int x,w;scanf("%d%d",&x,&w);all+=w-deep[x];tot++;change(x);}else if(op==2){int x;scanf("%d",&x);LL temp=all+ask(x)-deep[x]*tot;if(temp>delta[x])delta[x]=temp;}else if(op==3){int x;scanf("%d",&x);printf("%lld\n",all+ask(x)-deep[x]*tot-delta[x]);}}}return 0;
}

牛客多校7 - A National Pandemic(树链剖分+线段树)相关推荐

  1. 牛客练习赛26 E-树上路径 (树链剖分+线段树)

    链接:https://ac.nowcoder.com/acm/contest/180/E 来源:牛客网 树上路径 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语 ...

  2. 线段树 ---- 2021牛客多校第一场 J Journey among Railway Stations [线段树维护区间可行性判断]

    题目链接 题目大意: 一段路上有 NNN 个点,每个点有一个合法时间段[ui,vi][u_i,v_i][ui​,vi​],相邻两个点有一个长度wiw_iwi​.有qqq次询问,每次询问,在 [ui,v ...

  3. 牛客多校4 - Ancient Distance(树上倍增+dfs序+线段树)

    题目链接:点击查看 题目大意:给出一棵 n 个节点且以点 1 为根节点的的树,现在给出一个 k ,需要在树上选择 k 个关键点,使得 n 个点到达根节点的路径上,出现的最近的关键点的距离的最大值最小, ...

  4. 牛客小白月赛28 E-会当凌绝顶,一览众山小 线段树+二分暴力模拟

    牛客小白月赛28 E-会当凌绝顶,一览众山小 线段树+二分暴力模拟 题意 思路 Code 传送门: https://ac.nowcoder.com/acm/contest/16081/E 题意 登山顺 ...

  5. 牛客小白月赛9: D. 树上求和(dfs序+线段树)

    链接:https://ac.nowcoder.com/acm/contest/275/D 来源:牛客网 题目描述 给你一棵根为1的有N个节点的树,以及Q次操作. 每次操作诸如: 1 x y:将节点x所 ...

  6. 2019暑假牛客多校赛第九场H.Cutting Bamboos (主席树+二分)

    题意: 有n条柱子,高度为aia_iai​ ,我们有qqq次操作.在l到r的范围内砍yyy次,将所有的树高都砍为0,但是保证每一刀砍出来的长度(砍除树高于该高度的和)都是相同的.问你第xxx次砍的时候 ...

  7. 2021牛客多校6K Starch Cat(点分治+猫树)

    大意就是给一个树,给很多个问询,选择两个点之间的若干个点,在保证选择一个点后与其直接相连的点不能选,每次询问求总和最大值.必须在线. 最开始想的是树剖,但是做完签到后一看K题只有几个AC就果断run了 ...

  8. 2019暑期训练——牛客第七场 C. Governing sand(权值线段树)

    Governing sand 链接: https://ac.nowcoder.com/acm/contest/887/C 题意: 给n种树,其中每一种树都有高度h,每砍掉一棵树所需要的代价c,这种树的 ...

  9. 牛客多校三 B Black and white

    牛客多校三 B Black and white 在n*m的棋盘上,每个格子有一个数,初始可以选一定的格子标记为黑色,在任意四个形如(i1, j1)(i1, j2)(i2, j1)(i2, j2)的格子 ...

最新文章

  1. 紫书 习题 10-17 UVa 11105 (筛法)
  2. 深入浅出 MyBatis 的一级、二级缓存机制
  3. 网站优化数据分析不建议你遗落这三点
  4. windows server操作系统一定要关闭开机磁盘自检
  5. Android studio 修改包名 和 版本号
  6. python入门学习课程推荐
  7. asp.net开发 网络硬盘[转贴+删节]
  8. HTTP 错误 404.3 - Not Found 由于扩展配置问题而无法提供您请求的页面
  9. 在服务器托管中asp***的防范注意些什么?
  10. 【重难点】【JVM 01】OOM 出现的原因、方法区、类加载机制、JVM 中的对象
  11. [ASM]查看加密的vba代码
  12. spring接口 BeanFactoryAware,动态获取IOC容器里面的对象(多例)
  13. Linux设备管理(三):sysfs文件系统的功能及其应用
  14. win7系统中任务计划程序的使用与查询
  15. 微信小程序开发 网络异常监听
  16. 什么是字节对齐,为什么需要字节对齐
  17. java基于ssm的自助旅游管理系统
  18. 嵌入式的应用领域有哪些呢?
  19. OAI——单虚拟机多basic核心网部署
  20. postman 上传文件

热门文章

  1. java16下载_java lombok下载
  2. 怎么使图表居中显示_【Excel技巧】制作柱形图图表完美呈现百分比,提升您的报表颜值...
  3. 生产者消费者的实际使用
  4. 实例化Spring Bean:Bean实例化的姿势有多少种?
  5. 工厂方法模式适用场景
  6. 用户注册 - 判断用户名存在
  7. Log4j的FileAppender配置
  8. 区域数据导入功能(在服务端接收上传文件)
  9. Spring Session实战4
  10. spring的aop名词解释