cf276E 两棵线段树分别维护dfs序和bfs序,好题回头再做
搞了一晚上,错了,以后回头再来看
/*
对于每次更新,先处理其儿子方向,再处理其父亲方向
处理父亲方向时无法达到根,那么直接更新
如果能达到根,那么到兄弟链中去更新,使用bfs序
最后,查询结点v的结果就是dfs序线段树上的查询值+bfs线段树上的查询值
*/
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define maxn 150005
int n,q;
vector<int> mp[maxn]; struct node{
int u,depth;
}now,nex;
int depthL[maxn];//深度为i的下标最小的点
int depthR[maxn];//深度为i的下标最大的点
int num[maxn];//bfs序
int vis[maxn]; int L[maxn];//dfs入序
int R[maxn];//某结点为根的最大深度
int dist[maxn];
int cnt;
void Dfs(int u,int from,int dis){
L[u]=++cnt;
dist[u]=dis;
for(int i=;i<mp[u].size();i++){
int v=mp[u][i];
if(v==from) continue;
Dfs(v,u,dis+);
}
R[u]=cnt;
}
//处理bfs序的方法
void Bfs(){
int tot=;
queue<node>s;
now.u=,now.depth=;
s.push(now);
memset(depthL,-,sizeof depthL);
memset(depthR,,sizeof depthR);
memset(vis,,sizeof vis);
vis[]=;
while(!s.empty()){
tot++;
now=s.front();
s.pop();
num[now.u]=tot;
if(depthL[now.depth==-])
depthL[now.depth]=num[now.u];
depthR[now.depth]=max(depthR[now.depth],num[now.u]);
for(int i=;i<mp[now.u].size();i++){
int v=mp[now.u][i];
if(vis[v]==){
vis[v]=;
nex.u=v;
nex.depth=now.depth+;
s.push(nex);
}
}
}
}
//第一棵线段树处理dfs上的修改和查询,因为所有的子树都是链,其dfs连续,所以直接用线段树区间更新
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int tree[maxn<<];
int flag[maxn<<];
inline void pushup(int rt){
tree[rt]=tree[rt<<]+tree[rt<<|];
}
inline void pushdown(int l,int r,int rt){
if(flag[rt]){
int m=l+r>>;
flag[rt<<]+=flag[rt];
tree[rt<<]=(m-l+)*flag[rt];
tree[rt<<|]=(r-m)*flag[rt];
flag[rt]=;
}
}
void build(int l,int r,int rt){
tree[rt]=flag[rt]=;
if(l==r) return;
int m=l+r>>;
pushdown(l,r,rt);
build(lson);
build(rson);
pushup(rt);
}
void update(int L,int R,int c,int l,int r,int rt){
if(L<=l && R>=r){
tree[rt]+=(r-l+)*c;
flag[rt]+=c;
return;
}
int m=l+r>>;
pushdown(l,r,rt);
if(L<=m) update(L,R,c,lson);
if(R>m) update(L,R,c,rson);
pushup(rt);
}
//是单点查询
int query(int p,int l,int r,int rt){
if(l==r) return tree[rt];
int m=l+r>>;
pushdown(l,r,rt);
if(p<=m) return query(p,lson);
if(p>m) return query(p,rson);
pushup(rt);
} //第二棵线段树用来处理bfs上的修改和查询
//bfs序线段树也是通过访问顺序维护信息
int sum[maxn<<];
int flag2[maxn<<];
inline void pushup2(int rt){
sum[rt]=sum[rt<<]+sum[rt<<|];
}
inline void pushdown2(int l,int r,int rt){
if(flag2[rt]){
int m=l+r>>;
flag2[rt>>]+=flag2[rt];
flag2[rt>>|]+=flag2[rt];
sum[rt>>]+=(m-l+)*flag2[rt];
sum[rt>>|]+=(r-m)*flag2[rt];
flag2[rt]=;
}
}
void build2(int l,int r,int rt){
sum[rt]=flag2[rt]=;
if(l==r) return;
int m=l+r>>;
pushdown2(l,r,rt);
build(lson);
build(rson);
pushup2(rt);
}
void update2(int L,int R,int c,int l,int r,int rt){
if(L<=l && R>=r){
sum[rt]+=(r-l+)*c;
flag2[rt]+=c;
return;
}
int m=l+r>>;
pushdown2(l,r,rt);
if(L<=m) update(L,R,c,lson);
if(R>m) update(L,R,c,rson);
pushup2(rt);
}
int query2(int p,int l,int r,int rt){
if(l==r) return sum[rt];
int m=l+r>>;
pushdown2(l,r,rt);
if(p<=m) return query2(p,lson);
if(p>m) return query2(p,rson);
pushup2(rt);
} int main(){
while(scanf("%d%d",&n,&q)==){
for(int i=;i<=n;i++)
mp[i].clear();
for(int i=;i<=n-;i++){
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
cnt=;
Dfs(,-,);
Bfs();
build(,n,);
build2(,n,);
while(q--){
int op;
scanf("%d",op);
if(op==){//查询结点x的值
int x;
scanf("%d",&x);
printf("%d\n",query(L[x],,n,)+query2(num[x],,n,));
}
else {
int u,v,d;scanf("%d%d%d",&u,&v,&d);
if(u==){//如果是根结点,直接在兄弟结点上更新
if(depthR[d]!=)//这个深度是有节点的
update2(,depthR[d],v,,n,);
else //这个深度没有结点了,整棵树更新
update2(,n,v,,n,);
continue;
}
//如果不是根结点上更新
//先在dfs序上更新,注意
update(L[u],min(L[u]+d,R[u]),v,,n,);
if(d<dist[u])//如果根到u距离大于d,直接在链上更新
update(L[u]-d,L[u]-,v,,n,);
else {
//先从根维护到u的父亲
update(L[u]-(dist[u]-),L[u]-,v,,n,);
update(L[u]-(dist[u]-),min(L[u]-(dist[u]-)+(d-dist[u]-),R[u]),-v,,n,);//取消root到其兄弟结点相同深度的相应修改,因为接下去bfs序修改会重复
if(depthR[d-dist[u]]!=)//如果这个深度有结点
update2(,depthR[d-dist[u]],v,,n,);
else
update2(,n,v,,n,);
}
}
}
}
}
cf276E 两棵线段树分别维护dfs序和bfs序,好题回头再做的更多相关文章
- hdu 5861 Road 两棵线段树
传送门:hdu 5861 Road 题意: 水平线上n个村子间有 n-1 条路. 每条路开放一天的价格为 Wi 有 m 天的操作,每天需要用到村子 Ai~Bi 间的道路 每条路只能开放或关闭一次. ( ...
- BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)
原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力 ...
- CodeForces 587 E.Duff as a Queen 线段树动态维护区间线性基
https://codeforces.com/contest/587/problem/E 一个序列, 1区间异或操作 2查询区间子集异或种类数 题解 解题思路大同小异,都是利用异或的性质进行转化,st ...
- Codeforces J. A Simple Task(多棵线段树)
题目描述: Description This task is very simple. Given a string S of length n and q queries each query is ...
- UVA - 12424 Answering Queries on a Tree(十棵线段树的树链剖分)
You are given a tree with N nodes. The tree nodes are numbered from 1 to N and have colors C1, C2,. ...
- 【bzoj3533】[Sdoi2014]向量集 线段树+STL-vector维护凸包
题目描述 维护一个向量集合,在线支持以下操作:"A x y (|x|,|y| < =10^8)":加入向量(x,y);"Q x y l r (|x|,|y| < ...
- hdu 1556 Color the ball(线段树区间维护+单点求值)
传送门:Color the ball Color the ball Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/3276 ...
- CodeForces - 960F Pathwalks —— 主席树(n棵线段树)
题目链接:https://vjudge.net/problem/CodeForces-960F You are given a directed graph with n nodes and m ed ...
- 笔试算法题(27):判断单向链表是否有环并找出环入口节点 & 判断两棵二元树是否相等
出题:判断一个单向链表是否有环,如果有环则找到环入口节点: 分析: 第一个问题:使用快慢指针(fast指针一次走两步,slow指针一次走一步,并判断是否到达NULL,如果fast==slow成立,则说 ...
随机推荐
- 在同一个类中,一个方法调用另外一个有注解(比如@Async,@Transational)的方法,注解失效的原因和解决方法
参考原贴地址:https://blog.csdn.net/clementad/article/details/47339519 在同一个类中,一个方法调用另外一个有注解(比如@Async,@Trans ...
- mac下chrome快捷键
打开开发者工具:alt + command + I: 打开“JavaScript 控制台”:⌘-Option-J: 打开当前网页的源代码:⌘-Option-U: 刷新页面:command + R: m ...
- Linux记录-分区(df/fdisk/mount/umount/fuser)
1.查看磁盘挂载(df -TH) 2.卸载umount /dev/vdb1 3.查杀用户进程(fuser -m -v -i -k /dev/vdb1) 4.再次卸载umount /dev/vdb1,并 ...
- JAVA记录-SpringMVC scope属性的两种模式
singleton作用域:当把一个Bean定义设置为singleton作用域是,Spring IoC容器中只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean定义相匹配,则只 ...
- 【1】【JUC】JDK1.8源码分析之ArrayBlockingQueue,LinkedBlockingQueue
概要: ArrayBlockingQueue的内部是通过一个可重入锁ReentrantLock和两个Condition条件对象来实现阻塞 注意这两个Condition即ReentrantLock的Co ...
- Java编程思想 学习笔记1
一.对象导论 1.抽象过程 Alan Kay曾经总结了第一个成功的面向对象语言.同时也是Java所基于的语言之一的Smalltalk的五个基本特性,这些特性表现了纯粹的面向对象程序设计方式 1)万物皆 ...
- PHP7 学习笔记(六)403 Forbidden - WAMP Server 2.5
今天在wamp目录下有一个项目:comment 我在我的Windows 7机器上安装了WAMP版本2.5. 当浏览器浏览到本地主机时,WAMP服务器页面是可见的. 但是当我浏览到我的本地主机在我的移动 ...
- C# 部分类使用partial修饰
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace pati ...
- Maven聚合工程的使用
创建一个service模块 接下来,在该项目中创建一个接口 创建一个实现类,并实现接口 在sm1234-web项目中,调用service的方法,需要在该项目的pom.xml中引入依赖Service模块 ...
- Informatic学习总结_day01
1.forlder 必须open之后才出现 mapping的界面 2.Source Qualifer 3.小技巧 验证自己写的转换格式是否正确 提前过滤一些数据,informatica工具的本质也是 ...