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] ...
随机推荐
- AtCoder Regular Contest 061
AtCoder Regular Contest 061 C.Many Formulas 题意 给长度不超过\(10\)且由\(0\)到\(9\)数字组成的串S. 可以在两数字间放\(+\)号. 求所有 ...
- C++ 学习小程序之 map 的用法
1. map::at #include <iostream> #include <string> #include <map> using namespace st ...
- asp.net之ajax
ajax主要的作用是无刷新的情况进行提交. 常用于客户端组件信息的提交.服务器组件在asp.net中能够正常的提交,而html组件则不能正常提交,在此情况下,就可以采用jquery的方式进行数据的异步 ...
- linux下文件合并、分割、去重
1.文件合并 1.1文件上下合并 cat f1 f2> muti (将文件f1.f2合并成文件muti,f1在上,f2在下) 1.2左右合并 paste f1 f2 > muti (将 ...
- 制作OS X 10.10.3启动安装U盘
http://www.cnblogs.com/Bob-wei/p/4471407.html 1.获得“Install OS X Yosemite.app” 2.准备一个8GB的U盘,用磁盘工具“抹掉” ...
- Jfinal中定时器的初步探索(二)
第一篇中增加的是程序代码的实现,本篇我们将通过配置文件进行定时器的配置,减少代码量,提高灵活性. 1.需要用到的文件:quartz.properties,据说这个文件如果没有的话,按默认的走,结果布署 ...
- linux下安装svn
linux下SVN服务器如何搭建和使用 | 浏览:12117 | 更新:2013-09-18 14:28 | 标签:linux linux下SVN服务器如何搭建和使用?说到SVN服务器,想必大家都知道 ...
- Nginx实现静态资源的缓存
1.1 需求 1.对静态文件进行缓存:html,js,css,png,gif,jpg,jpeg,bmp,swf. 2.对符合url规则的请求进行缓存. 3.针对某个url进行清除缓存. 1.1 ...
- Python(正则 Time datatime os sys random json pickle模块)
正则表达式: import re #导入模块名 p = re.compile(-]代表匹配0至9的任意一个数字, 所以这里的意思是对传进来的字符串进行匹配,如果这个字符串的开头第一个字符是数字,就代表 ...
- DIV的垂直居中
一直以来都没有找到一种完美解决DIV垂直居中的方法,今天终于找到了,特记录如下,从此不再用table来居中了.^^ <html> <style> #image{ width:5 ...