首页 > 其他分享 >3853 -- 三只企鹅

3853 -- 三只企鹅

时间:2023-05-11 20:55:19浏览次数:35  
标签:dep 企鹅 200005 -- long son int 3853 id

题目大意:
- 给定一棵 n 个点的树,然后有 m 个操作,分为修改操作和查询操作。
- 修改操作:金企鹅向点 u 空投零食,其他每个点产生快递费,快递费等于 u 到该点的距离。
- 查询操作:金企鹅想询问点 u 至今为止产生的快递费。

------------

题解:对于修改操作,每次选一个点,所有点的权值加上到该点的距离,如果暴力修改显然超时。

我们可以先考虑这样一个问题: 选择出点u,那么一个指定点v产生的贡献是多少?答案是 : $dep[u]+dep[v]-2*dep[lca(u,v)]$

这是一对点,如果多次修改呢?

显然我们可以把上面式子拆成两个部分设某次查询操作之前选了这些点空头:{ $s_1$ , $s_2$ , $s_3$ ,....., $s_n$ }

那么 $dep[u]$ 就是: $\sum_{i=1}^ndep[s_i]$ $\ $ 这个可以记下来。

 $\qquad $ $dep[v]$ 就是:$n*dep[v]$ $\ $ 这个可以查询的时候直接计算
 
 那么剩下我们就只需要统计: $ 2*\sum_{i=1}^ndep[lca(s_i,v)] $ 就是所有的 $lca$ 的深度和。
 
 你发现一个点的深度其实是这个点到根节点上所有的边权和,两个点的 $lca$ 的深度就是重合部分,我们考虑把边权下放到点上,那选出点时就可以把这个点到根节点上所有的点都加上相对应的边权,查询的时候就是求出这个点到根节点上所有的权值和。问题就转化成了树上一条链上区间加和区间求和,很自然的想到**树链剖分**。
 
 最后线段树你可能会对状态的设置产生一些疑问,可以设 $s$ 表示总和, $sum$ 表示对应的点权(边权)和, $lazy$ 表示这个区间加了多少次,每次 $pushdown$ 的时候就 $s+=sum*lazy$ 表示直接加上这个区间。本题就做完了。附代码。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
struct stu{
  int y,z;
};
vector<stu>p[200005];
long long dd[200005];
int dep[200005];
int siz[200005],son[200005],tp[200005],fa[200005],id[200005],rk[200005],tot=0;
int qz[200005];
void dfs1(int i,int ff){
  fa[i]=ff;
  dep[i]=dep[ff]+1;
  siz[i]=1;
  for(int j=0;j<p[i].size();j++){
    int to=p[i][j].y,val=p[i][j].z;
    if(to==ff)continue;
    qz[to]=val;
    dd[to]=dd[i]+val;
    dfs1(to,i);
    siz[i]=siz[i]+siz[to];
    if(siz[to]>siz[son[i]])son[i]=to;
  }
}
void dfs2(int i,int top){
  tp[i]=top;
  id[i]=++tot;
  rk[tot]=i;
  if(son[i])dfs2(son[i],top);
  for(int j=0;j<p[i].size();j++){
    int to=p[i][j].y;
    if(to==son[i]||to==fa[i])continue;
    dfs2(to,to);
  }
}
long long ans1=0,gs=0,ans2=0;
long long sum[200005*4],lazy[200005*4],tree[200005*4];
void build(int k,int l,int r){
  if(l==r){
    sum[k]=qz[rk[l]];
    return;
  }
  int mid=(l+r)/2;
  build(k*2,l,mid);
  build(k*2+1,mid+1,r);
  sum[k]=sum[k*2]+sum[k*2+1];
}
void pushdown(int k){
  if(lazy[k]){
    lazy[k*2]+=lazy[k];
    lazy[k*2+1]+=lazy[k];
    tree[k*2]+=sum[k*2]*lazy[k];
    tree[k*2+1]+=sum[k*2+1]*lazy[k];
    lazy[k]=0;
  }
}
void xg(int k,int l,int r,int L,int R,int val){
  if(l>R||r<L)return;
  if(l>=L&&r<=R){
    lazy[k]++;
    tree[k]+=sum[k];
    return;
  }
  pushdown(k);
  int mid=(l+r)/2;
  xg(k*2,l,mid,L,R,val);
  xg(k*2+1,mid+1,r,L,R,val);
  tree[k]=tree[k*2]+tree[k*2+1];
}
long long query(int k,int l,int r,int L,int R){
  if(l>R||r<L)return 0;
  if(l>=L&&r<=R)return tree[k];
  pushdown(k);
  int mid=(l+r)/2;
  long long res=0;
  res=res+query(k*2,l,mid,L,R);
  res=res+query(k*2+1,mid+1,r,L,R);
  return res;
}
void change(int x,int y,int u){
  while(tp[x]!=tp[y]){
    if(dep[tp[x]]<dep[tp[y]])swap(x,y);
    xg(1,1,n,id[tp[x]],id[x],dd[u]);
    x=fa[tp[x]];
  }
  if(id[x]>id[y])swap(x,y);
  xg(1,1,n,id[x],id[y],dd[u]);
}
long long qquery(int x,int y){
  long long res=0;
  while(tp[x]!=tp[y]){
    if(dep[tp[x]]<dep[tp[y]])swap(x,y);
    res=res+query(1,1,n,id[tp[x]],id[x]);
    x=fa[tp[x]];
  }
  if(id[x]>id[y])swap(x,y);
  res=res+query(1,1,n,id[x],id[y]);
  return res;
}
int main(){
  // freopen("4.in","r",stdin);
  // freopen("4.out","w",stdout);
  scanf("%d%d",&n,&m);
  for(int i=1;i<n;i++){
    int n1,n2,n3;
    scanf("%d%d%d",&n1,&n2,&n3);
    p[n1].push_back((stu){n2,n3});
    p[n2].push_back((stu){n1,n3});
  }
  dfs1(1,1);
  dfs2(1,1);
  build(1,1,n);
  while(m--){
    int opt,u;
    scanf("%d%d",&opt,&u);
    if(opt==1){
      gs++;
      ans1=ans1+dd[u];
      change(u,1,u);
    }else {
      ans2=ans1+gs*dd[u];
      ans2=ans2-2*qquery(u,1);
      printf("%lld\n",ans2);
    }
  }
  return 0;
}

 



本题和1988染色本质一样,只是1988一个点只能贡献一次,所以需要开个数组记一下防止加重。(~~双倍经验~~)

标签:dep,企鹅,200005,--,long,son,int,3853,id
From: https://www.cnblogs.com/happy-XQJ/p/17392206.html

相关文章

  • 使用Open3D进行PCD拟合平面的Python代码示例
    使用Open3D进行PCD拟合平面的Python代码示例 importopen3daso3dimportnumpyasnp#读取点云数据pcd=o3d.io.read_point_cloud("2023042501.pcd")#创建PCD图pcd_graph=o3d.geometry.PointCloudGraph(pcd)#选择要拟合的平面plane_cent......
  • MongoDB整理
    MongoDB一、数据库(database)①什么是数据库?存储数据的仓库②为什么要有数据库?数据持久化③数据库能做什么?存储数据,可以通过网络访问④数据库的分类按照关系型分类:1、关系型数据库(MySQL、Oracle等)2、非关系型数据库(MongoDB、Redis)区别:关系型是创建表格,非关系型......
  • PyQt5入门
    要使用pyqt5需要先导入对应的包pipinstallPyQt5pipinstallPyQt5-tools然后编写我们的第一个程序fromPyQt5.QtWidgetsimport*fromPyQt5.QtGuiimport*fromPyQt5.QtCoreimport*importsysclassMyWindow(QWidget):def__init__(self):super().__i......
  • 每日总结 5.11
    <!doctypehtml><html><head><metacharset="UTF-8"><scripttype='text/javascript'>if(document.createElement("input").webkitSpeech===undefined){ale......
  • 1016. 子串能表示从 1 到 N 数字的二进制串
    题目链接:1016.子串能表示从1到N数字的二进制串方法:思维解题思路 由题目可知,字符串\(s\)的最大长度为\(1000\),那么其最多能表示的不同的二进制数不超过\(1000\)个。因此当\(n>1000\)时,直接返回\(false\);否则遍历\([1,n]\)判断是否符合题意。代码classSolu......
  • 转录组
    转录组是指一个生物体内所有基因在特定时期和特定组织或细胞类型中表达出的所有信使RNA(mRNA)的集合。换句话说,转录组是一个生物体内所有基因的转录产物总和。转录组分析一般通过测量mRNA的水平来实现,通常使用高通量测序技术如RNA-Seq,以了解哪些基因在特定条件下被激活或抑制,并......
  • Python协程asyncio
    在Python使用multiprocessing进行多线程和多进程操作 这篇文章中介绍了使用多线程的方式对一些I/O操作(文件读写、网络请求,这些操作不用等待其结束,在此期间可以做其他事情)进行加速。而本篇文章介绍的协程可以理解成“微线程”,不开辟其他线程,只在一个线程中执行,并且执行函数时......
  • 8.6 空间直线、平面的垂直
    \(\mathbf{{\large{\color{Red}{欢迎到学科网下载资料学习}}}}\)【高分突破系列】高一数学下学期同步知识点剖析精品讲义!\(\mathbf{{\large{{\color{Red}{跟贵哥学数学,so\quadeasy!}}}}}\)必修第二册同步拔高,难度3颗星!模块导图知识剖析线线垂直1异面直线所......
  • MySQL外键约束和多表查询
    外键约束和多表查询一、外键是什么图解![image-20230429113839805](file://D:\大数据基础班\03_随堂资料\day05\笔记\day05_外键约束和多表查询.assets\image-20230429113839805.png?lastModify=1683721071)知识点外键:多个表之间的关联字段特点1:从表外键的值是对主表主......
  • Linux cpuidle framework(1)_概述和软件架构
    1.前言在计算机系统中,CPU的功能是执行程序,总结起来就是我们在教科书上学到的:取指、译码、执行。那么问题来了,如果没有程序要执行,CPU要怎么办?也许您会说,停掉就是了啊。确实,是要停掉,但何时停、怎么停,却要仔细斟酌,因为实际的软硬件环境是非常复杂的。我们回到Linuxkernel上,Linux......