HDU5221 Occupation 树链剖分
题意:
给出一棵树,root=1,树有点权,有一个人叫做M
有3种操作:
1 u v 把u到v路径上的所有点的点权都给M
2 u 若u的点权在M手上,拿走
3 u 把u为根的子树的所有点权都给M
每一个操作过后,输出M拥有的点权
想法:
要维护路径,用树链剖分
要维护子树,用dfs序
但是这样貌似要写很多
然而后来知道
树链剖分是有dfs序的,也就是说,树链剖分后,对于一个点,其子树所有点的新编号刚好在该点新编号后面的一个连续的区间里面,这个区间的范围[chg[u],chg[u]+siz[u]-1],
这样的话就方便了,我们只需要一个树链剖分就可以了。
树链剖分后用线段树维护,
线段树维护3个值:
all:若区间都被M拥有了,all为1,否则为0
val:在该区间内,M拥有的所有点权的和
sum:在该区间内,所有点的点权的和
(sum在build后就是固定的,不需要再更改)
我们只需要update2个:all和val
这样每一次update后,答案就是seg[1].val了
其实刚开始的时候我只维护2个值:all和sum
然后每一次update操作后我就query一次求出val,然而这样肯定超时啊
加了个val后query函数就直接省略了
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> #define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 using namespace std; const int maxn=1e5+;
const int inf=0x3f3f3f3f; struct Seg
{
int all,val,sum;
};
Seg seg[maxn<<]; int a[maxn];
int dep[maxn];
int siz[maxn];
int son[maxn];
int fa[maxn];
int top[maxn];
int chg[maxn];
int rev[maxn]; struct Edge
{
int to,next;
};
Edge edge[maxn<<];
int head[maxn];
int tot; void init()
{
memset(head,-,sizeof head);
tot=;
} void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
} void solve(int ); int main()
{
int test;
scanf("%d",&test);
while(test--){
int n;
scanf("%d",&n);
init();
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
addedge(u,v);
addedge(v,u);
}
solve(n);
}
return ;
} void dfs0(int u,int pre)
{
fa[u]=pre;
siz[u]=;
dep[u]=dep[pre]+;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==pre)
continue;
dfs0(v,u);
siz[u]+=siz[v];
if(son[u]==- || siz[v]>siz[son[u]])
son[u]=v;
}
} void dfs1(int u,int tp)
{
top[u]=tp;
chg[u]=++tot;
rev[tot]=u;
if(son[u]==-)
return ;
dfs1(son[u],tp);
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==fa[u] || v==son[u])
continue;
dfs1(v,v);
}
} void pushup(int rt)
{
seg[rt].val=seg[rt<<].val+seg[rt<<|].val;
} void build(int l,int r,int rt)
{
seg[rt].sum=seg[rt].all=seg[rt].val=;
if(l==r){
seg[rt].sum=a[rev[l]];
return ;
}
int m=(l+r)>>;
build(lson);
build(rson);
seg[rt].sum=seg[rt<<].sum+seg[rt<<|].sum;
} void pushdown(int rt)
{
if(seg[rt].all){
seg[rt<<].all=seg[rt<<|].all=;
seg[rt<<].val=seg[rt<<].sum;
seg[rt<<|].val=seg[rt<<|].sum;
seg[rt].all=;
}
} void update_seg(int L,int R,int add,int l,int r,int rt)
{
if(L<=l&&R>=r){
seg[rt].all=add;
if(add)
seg[rt].val=seg[rt].sum;
else
seg[rt].val=;
return ;
}
int m=(l+r)>>;
pushdown(rt);
if(L<=m)
update_seg(L,R,add,lson);
if(R>m)
update_seg(L,R,add,rson);
pushup(rt);
} void update_path(int u,int v)
{
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])
swap(u,v);
update_seg(chg[top[u]],chg[u],,,tot,);
u=fa[top[u]];
}
if(dep[u]<dep[v])
swap(u,v);
update_seg(chg[v],chg[u],,,tot,);
} void solve(int n)
{
memset(son,-,sizeof son);
memset(dep,,sizeof dep);
dfs0(,);
tot=;
dfs1(,); build(,tot,);
int q;
scanf("%d",&q);
for(int i=;i<=q;i++){
int op;
scanf("%d",&op);
if(op==){
int u,v;
scanf("%d %d",&u,&v);
update_path(u,v);
}
else{
int u;
scanf("%d",&u);
if(op==){
update_seg(chg[u],chg[u],,,tot,);
}
else{
update_seg(chg[u],chg[u]+siz[u]-,,,tot,);
}
}
printf("%d\n",seg[].val);
}
return ;
}
HDU5221 Occupation 树链剖分的更多相关文章
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 1984: 月下“毛景树” [树链剖分 边权]
1984: 月下“毛景树” Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 1728 Solved: 531[Submit][Status][Discu ...
- codevs 1228 苹果树 树链剖分讲解
题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...
- 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)
题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...
- 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)
题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...
- 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)
题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...
- bzoj2243树链剖分+染色段数
终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...
- bzoj3631树链剖分
虽然是水题1A的感觉太爽了O(∩_∩)O~ 题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值 本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...
- BZOJ 3531: [Sdoi2014]旅行 [树链剖分]
3531: [Sdoi2014]旅行 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1685 Solved: 751[Submit][Status] ...
随机推荐
- php 倒计时程序
<html> <head> <meta http-equiv="Content-Type" content="text/html; ch ...
- UI组件(思维导图)
- SQL书写规范及常用SQL语句
常用的查询语句 SELECT * FROM 表名 [WHERE 条件 或 GROUP BY 字段名 HAVING] ORDER BY 字段名 排序方式 LIMIT 初始值,数量; SELECT fna ...
- 配置Apache将自己的电脑做服务器使局域网内的电脑访问自己的主机
很多的朋友都想把自己的电脑打造为服务器使别人能够访问.比如说你自己写了一网站,只能自己通过localhost访问或127.0.0.1访问.但是怎么让别人的电脑也能访问呢?来看看自己写的网站.现在我来讲 ...
- 文件与目录的默认权限与隐藏权限【转vbird】
一个文件有若干个属性, 包括读写运行(r, w, x)等基本权限,及是否为目录 (d) 与文件 (-) 或者是连结档 (l) 等等的属性! 要修改属性的方法在前面也约略提过了(chgrp, chown ...
- Twsited异步网络框架
Twisted是一个事件驱动的网络框架,其中包含了诸多功能,例如:网络协议.线程.数据库管理.网络操作.电子邮件等. Twisted介绍:http://blog.csdn.net/hanhuili/a ...
- Oracle数据库——Scheduler Job
日常的运维工作中,我们经常使用Linux Server的anacron服务来使得服务器执行一下计划之内的任务,可以按照特定的时间间隔,重复的执行相关的命令或者相关的脚本,来完成预期的目标,能够节省相关 ...
- MySQL中行列转换的SQL技巧
行列转换常见场景 由于很多业务表因为历史原因或者性能原因,都使用了违反第一范式的设计模式.即同一个列中存储了多个属性值(具体结构见下表). 这种模式下,应用常常需要将这个列依据分隔符进行分割,并得到列 ...
- json解析:[2]fastjson 使用
利用阿里的fastjson包对对象进行 json的转化与解析,本篇为第二篇,第一篇讲述的是利用gson进行json数据解析,地址:jingyan.baidu.com/article/e8cdb32b6 ...
- 转(linux shell)(2)
http://oldboy.blog.51cto.com/2561410/1665163 1.按单词出现频率降序排序! 2.按字母出现频率降序排序! the squid project provi ...