题意:

给出一棵树,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 树链剖分的更多相关文章

  1. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  2. BZOJ 1984: 月下“毛景树” [树链剖分 边权]

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1728  Solved: 531[Submit][Status][Discu ...

  3. codevs 1228 苹果树 树链剖分讲解

    题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...

  4. 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)

    题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...

  5. 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)

    题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...

  6. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  7. bzoj2243树链剖分+染色段数

    终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...

  8. bzoj3631树链剖分

    虽然是水题1A的感觉太爽了O(∩_∩)O~ 题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值 本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...

  9. BZOJ 3531: [Sdoi2014]旅行 [树链剖分]

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1685  Solved: 751[Submit][Status] ...

随机推荐

  1. linux 命令-全称

    cal = CALendar calendar日历, 历法cat = CATenate 连接, 使连续cd = Change Directorychgrp = CHange GRouPchmod =  ...

  2. 编写linux驱动所用到的头文件(转)

    转自:http://blog.csdn.net/lufeiop02/article/details/6448497 关于linux驱动(应用)程序头文件使用 收藏 驱动程序: #include < ...

  3. (转)一文学会用 Tensorflow 搭建神经网络

    一文学会用 Tensorflow 搭建神经网络 本文转自:http://www.jianshu.com/p/e112012a4b2d 字数2259 阅读3168 评论8 喜欢11 cs224d-Day ...

  4. Data Pump(数据抽取)介绍

    从10g开始,Oracle提供更高效的Data Pump(即expdp/impdp)来进行数据的导入和导出,老的exp/imp还可以用,但已经不建议使用.注意:expdp/impdp和exp/imp之 ...

  5. 轮播图切换 纯html+js+css

    如图所示. 该图片切换特效实现很简单,而且兼容性很好. html页面如下 复制代码代码如下: <div class="wrapper"> <div id=&quo ...

  6. Nginx重写规则指南 转

    http://www.ttlsa.com/nginx/nginx-rewriting-rules-guide/ Nginx重写规则指南 当运维遇到要重写情况时,往往是要程序员把重写规则写好后,发给你, ...

  7. python datetime

    不管何时何地,只要我们编程时遇到了跟时间有关的问题,都要想到 datetime 和 time 标准库模块,今天我们就用它内部的方法,详解python操作日期和时间的方法.1.将字符串的时间转换为时间戳 ...

  8. Onload,Onunload,onbeforeunload,$(window).load(function() {})和$(document).ready(function(){})

    Onload,$(window).load(function() {}):元素都加载完毕,才可以执行. $(document).ready(function(){}):不一定要等所有的js和图片加载完 ...

  9. 001. 启动Visual Studio 2010报错

    错误内容: 外接程序"VMDebugger"未能加载或导致了异常. 是否希望移除该外接程序? 错误号: 80004005 如下图: 解决办法一: 1. 点击 是 打开VS2010, ...

  10. 获取Asp.net GridView控件当中总的记录数量

    问题: 解决方案: SqlDataSource 或 AccessDataSource的selected事件的e.AffectedRows为查询操作返回的数据数目.(这个是在gridview分页情况下采 ...