Codeforces 396C (DFS序+线段树)
题面
传送门
题目大意:
给定一棵树,每个点都有权值,边的长度均为1,有两种操作
操作1:将节点u的值增加x,并且对于u的子树中的任意一个点v,将它的值增加x-dist(u,v)*k, dist(u,v)表示u,v之间的距离
操作2:查询节点u的值
分析
这类题目需要用到一个重要的思想:将树上操作转化为区间操作
通过DFS序我们可以实现这一点.
对于每个节点x,我们记录它在前序遍历中的位置l[x],再一次回到x时的序号r[x],则x及其子树的区间为前序遍历中的[l[x],r[x]]
如:
这棵树的前序遍历为0 1 4 5 2 6 3 7 8 9 10
后序遍历为4 5 1 6 2 7 8 9 10 3 0
对于点3来说,它在前序遍历中的序号为7,遍历完7,8,9后回到3的序号为10,则区间为[7,10]
将树上操作转化为区间之后,我们处理两种操作
显然是用线段树的区间修改和单点查询实现
每次修改时,对于u的后代v,我们发现它增加的值=x+k(d[v]−d[u])=x+k×d[u]−k×d[v]" role="presentation" style="position: relative;">=x+k(d[v]−d[u])=x+k×d[u]−k×d[v]=x+k(d[v]−d[u])=x+k×d[u]−k×d[v] (d[x]表示x的深度)
其中,对于u的每个后代v,x+k×d[u]" role="presentation" style="position: relative;">x+k×d[u]x+k×d[u]都是一样的,可以批量修改,而k×d[v]" role="presentation" style="position: relative;">k×d[v]k×d[v]则由每个节点决定
因此,我们用两棵线段树维护
一棵维护x+k×d[u]" role="presentation" style="position: relative;">x+k×d[u]x+k×d[u],一棵维护k" role="presentation" style="position: relative;">kk
修改时,我们把x+k×d[u]" role="presentation" style="position: relative;">x+k×d[u]x+k×d[u]和k" role="presentation" style="position: relative;">kk分别累加到区间[l[u],r[u]]中每一个点
查询时,我们可以求出每个节点的x+k×d[u]" role="presentation" style="position: relative;">x+k×d[u]x+k×d[u]的总和a,以及k" role="presentation" style="position: relative;">kk的总和b
答案就是a−b∗d[u]" role="presentation" style="position: relative;">a−b∗d[u]a−b∗d[u]
时间复杂度O(n+qlog2n)" role="presentation" style="position: relative;">O(n+qlog2n)O(n+qlog2n)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 300005
#define mod 1000000007ll
using namespace std;
int n,q;
struct edge{
int from;
int to;
int next;
}E[maxn<<1];
int size;
int head[maxn];
void add_edge(int u,int v){
size++;
E[size].from=u;
E[size].to=v;
E[size].next=head[u];
head[u]=size;
}
struct segment_tree{
struct node{
int l;
int r;
long long mark;
long long v;
}tree[maxn<<2];
segment_tree(){
memset(tree,0,sizeof(tree));
}
void build(int l,int r,int pos){
tree[pos].l=l;
tree[pos].r=r;
tree[pos].mark=0;
tree[pos].v=0;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,pos<<1);
build(mid+1,r,pos<<1|1);
}
void push_down(int pos){
if(tree[pos].mark){
tree[pos<<1].mark=(tree[pos].mark+tree[pos<<1].mark)%mod;
tree[pos<<1|1].mark=(tree[pos].mark+tree[pos<<1|1].mark)%mod;
tree[pos<<1].v=(tree[pos].mark+tree[pos<<1].v)%mod;
tree[pos<<1|1].v=(tree[pos].mark+tree[pos<<1|1].v)%mod;
tree[pos].mark=0;
}
}
void update(int L,int R,long long v,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
tree[pos].v=(tree[pos].v+v)%mod;
tree[pos].mark=(tree[pos].mark+v)%mod;
return ;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
if(L<=mid) update(L,R,v,pos<<1);
if(R>mid) update(L,R,v,pos<<1|1);
return;
}
long long query(int L,int R,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
return tree[pos].v;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
long long ans=0;
if(L<=mid) ans=(ans+query(L,R,pos<<1))%mod;
if(R>mid) ans=(ans+query(L,R,pos<<1|1))%mod;
return ans;
}
};
segment_tree T1,T2;
int l[maxn],r[maxn];
int deep[maxn];
int cnt=0;
void dfs(int x,int fa){
l[x]=++cnt;
deep[x]=deep[fa]+1;
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
if(y!=fa){
dfs(y,x);
}
}
r[x]=cnt;
}
int main(){
int p,cmd;
int v,x,k;
scanf("%d",&n);
int root;
for(int i=2;i<=n;i++){
scanf("%d",&p);
add_edge(i,p);
add_edge(p,i);
}
dfs(1,0);
T1.build(1,n,1);
T2.build(1,n,1);
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d",&cmd);
if(cmd==1){
scanf("%d %d %d",&v,&x,&k);
T1.update(l[v],r[v],(long long)x+(long long)deep[v]*k%mod,1);
T2.update(l[v],r[v],(long long)k,1);
}else{
scanf("%d",&v);
long long ans=(T1.query(l[v],l[v],1)-(long long)deep[v]*T2.query(l[v],l[v],1)+mod)%mod;
if(ans<0) ans+=mod;
printf("%I64d\n",ans%mod);
}
}
}
Codeforces 396C (DFS序+线段树)的更多相关文章
- CodeForces 877E DFS序+线段树
CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...
- Codeforces 1110F(DFS序+线段树)
题面 传送门 分析 next_id = 1 id = array of length n filled with -1 visited = array of length n filled with ...
- Codeforces 1132G(dfs序+线段树)
题面 传送门 分析 对于每一个数a[i],找到它后面第一个大于它的数a[p],由p向i连边,最终我们就会得到一个森林,且p是i的父亲.为了方便操作,我们再增加一个虚拟节点n+1,把森林变成树. 由于序 ...
- Educational Codeforces Round 6 E dfs序+线段树
题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...
- Codeforces 343D Water Tree(DFS序 + 线段树)
题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...
- Codeforces Round #442 (Div. 2)A,B,C,D,E(STL,dp,贪心,bfs,dfs序+线段树)
A. Alex and broken contest time limit per test 2 seconds memory limit per test 256 megabytes input s ...
- CodeForces 877E Danil and a Part-time Job(dfs序+线段树)
Danil decided to earn some money, so he had found a part-time job. The interview have went well, so ...
- 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心
3252: 攻略 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 339 Solved: 130[Submit][Status][Discuss] D ...
- BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)
题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...
随机推荐
- WPF导出发布安装包,无法验证发行者解决办法
右击工程项目点发布->完成 此时在工程目录下生成了安装文件setup.exe 同时又在工程下生成了临时证书WpfApp1_TemporaryKey.pfx 如果此时强行安装会弹出如下警告 接下来 ...
- 阅读《Effective Java》每条tips的理解和总结(1)
<Effective Java>这本书的结构是90来条tips,有长有短,每条tip都值的学习.这里根据对书中每条tip的理解做简短的总结,方便日后回顾.持续更新~ 1. 考虑用静态方法代 ...
- hadoop2.7伪分布式搭建
0.配置主机名 hostnamectl set-hostname spark1 1.上传hadoop-2.7.1.tar.gz文件并解压 tar -xvf hadoop-2.7.1.tar.gz 2. ...
- github上.md的编写
# algs4 一:大标题 =========== 二:中标题 ------------ 三:1~6级标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 # ...
- 【Java】SpringBoot整合RabbitMQ
介绍 RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用. RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,AMQP,即A ...
- Pandas中的qcut和cut
qcut与cut的主要区别: qcut:传入参数,要将数据分成多少组,即组的个数,具体的组距是由代码计算 cut:传入参数,是分组依据.具体见示例 1.qcut方法,参考链接:http://panda ...
- Move Controller UE4键位
工作中需要,就总结了一下,如下图:
- php中钩子(hook)的应用示例demo
我们先来回顾下原本的开发流程:产品汪搞出了一堆需求:当用户注册成功后需要发送短信.发送邮件等等:然后聪明机智勇敢的程序猿们就一扑而上:把这些需求转换成代码扔在 用户注册成功 和 跳转到首页 之间: 没 ...
- 使用innobackupex基于从库搭建级联从库及一两从
使用innobackupex基于从库搭建mysql主从架构 现有的架构是一主一从,版本为Mysql5.6.37.实施要求是:利用从库,搭建第二个从库,版本为5.7.21 主库:192.168.1.21 ...
- Redis 简介,安装,卸载
一.Redis简介 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(s ...