题意:

给出一棵树,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. php随笔杂记(一)

    1.在function updatepwd($postData=array())   如果参数是一个数组, 在使用时,如果给他赋值则只返回数组名$postData即可  ,如果里面已有值 ,这返回的可 ...

  2. Python笔记本

    Python 的主提示符( >>> )和次提示符( ... ).主提示符是解释器告诉你它在等你输入下一个语句,次提示符告诉你解释器正在等待你输入当前语句的其它部分. 下划线(_)在解 ...

  3. JS原型链原理(链表)

      任何一个对象都有一个prototype的属性,在js中可以把它记为:__proto__   当初ECMAscript的发明者为了简化这门语言,同时又保持继承的属性,于是就设计了这个链表..在数据结 ...

  4. Android——单元测试

    在实际开发中,开发android软件的过程需要不断地进行测试.而使用Junit测试框架,侧是正规的Android开发的必用技术,在Junit中可以得到组件,可以模拟发送事件和检测程序处理的正确性. 第 ...

  5. Twitter 登录和分享

    继上面一片介绍了FaceBook的登录和分享,现在再来实现Twitter的登录和分享. 1.首先要说明的是,我没找到官方提供的SDK,查阅很多文章都提到了一个帮助实现的包Twitter4j.jar   ...

  6. python模块结构和布局

    用模块来合理的组织你的python代码是简单又自然的方法.下面介绍一种非常合理的布局: #(1)起始行(Unix) #(2)模块文档 #(3)模块导入 #(4)变量定义 #(5)类定义 #(6)函数定 ...

  7. 自定义Mvc5 Owin 验证

    public class AuthIn : IUserAuthenticate { public static ApplicationUserManager UserManager { get { r ...

  8. linux概念之进程分析

    http://blog.csdn.net/kevinx_xu/article/details/8178746 /proc 详解 内核线程分析报告 进程层次 [root@109-com1 scripts ...

  9. Python关键字yield的解释(stackoverflow)

    3.1. 提问者的问题 Python关键字yield的作用是什么?用来干什么的? 比如,我正在试图理解下面的代码: def node._get_child_candidates(self, dista ...

  10. ZooKeeper伪分布集群安装及使用 RMI+ZooKeeper实现远程调用框架

    使用 RMI + ZooKeeper 实现远程调用框架,包括ZooKeeper伪集群安装和代码实现两部分.  一.ZooKeeper伪集群安装: 1>获取ZooKeeper安装包 下载地址:ht ...