【BZOJ-3589】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)
3589: 动态树
Time Limit: 30 Sec Memory Limit: 1024 MB
Submit: 405 Solved: 137
[Submit][Status][Discuss]
Description
Input
Output
对于每个事件1, 输出询问的果子数.
Sample Input
1 2
2 3
2 4
1 5
3
0 1 1
0 2 3
1 2 3 1 1 4
Sample Output
HINT
1 <= n <= 200,000, 1 <= nQ <= 200,000, K = 5.
生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.
Source
Solution
真丶动态树,直接用树链剖分水过
首先树链剖分不解释,子树修改?水过
在于查询多段路径的并。
一开始想的是这不直接覆盖么...然后水水的一波..打完发现哦,这是树,不能这么搞...
难道真的要写LCT?其实不用...
思考可以在路径上的点打标记,沿着有标记的路径求和?似乎可以,但没实现
对于路径的求并,可以考虑容斥原理,应该很优,但是不会TAT
所以是某奇怪的姿势:
线段覆盖!详见CodeVS线段覆盖..
很显然,对于树链剖分,是把树上的点映射到序列上,那么对于路径的询问其实就是路径上的多段区间的询问
多次询问就是多次多段区间的询问,考虑直接把这些区间拿出来,然后利用线段覆盖的姿势合并这些区间,对合并后的统计答案即可
这里结果会很大,所以可以让结果自然溢出,最后结果&MaxInt可以变回正数,int的自然溢出是在$-2^{31}-0$循环,unsignedint的是在$-2^{32}-0$循环
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define maxn 210000
int n,q;
struct Edgenode{int to,next;}edge[maxn<<];
int head[maxn],cnt=;
void add(int u,int v){cnt++; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt;}
void insert(int u,int v){add(u,v); add(v,u);}
//
//int fa[maxn],son[maxn],deep[maxn],size[maxn],pl[maxn],sz,pr[maxn],pre[maxn],top[maxn];
int fa[maxn],top[maxn],son[maxn];
int size[maxn],pl[maxn],pr[maxn],sz,pre[maxn],deep[maxn];
void dfs_1(int now)
{
size[now]=;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=fa[now])
{
fa[edge[i].to]=now;
deep[edge[i].to]=deep[now]+;
dfs_1(edge[i].to);
if (size[son[now]]<size[edge[i].to]) son[now]=edge[i].to;
size[now]+=size[edge[i].to];
}
}
void dfs_2(int now,int chain)
{
pl[now]=++sz;pre[sz]=now;top[now]=chain;
if (son[now]) dfs_2(son[now],chain);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=son[now] && edge[i].to!=fa[now])
dfs_2(edge[i].to,edge[i].to);
pr[now]=sz;
}
//
struct Treenode{int l,r,size,sum,tag;}tree[maxn<<];
void update(int now)
{
tree[now].sum=tree[now<<].sum+tree[now<<|].sum;
}
void pushdown(int now)
{
if (tree[now].tag)
{
tree[now<<].tag+=tree[now].tag;tree[now<<|].tag+=tree[now].tag;
tree[now<<].sum+=tree[now].tag*tree[now<<].size;
tree[now<<|].sum+=tree[now].tag*tree[now<<|].size;
tree[now].tag=;
}
}
void build(int now,int l,int r)
{
tree[now].l=l; tree[now].r=r; tree[now].size=r-l+;
tree[now].tag=; tree[now].sum=;
if (l==r) return;
int mid=(l+r)>>;
build(now<<,l,mid); build(now<<|,mid+,r);
update(now);
}
void change(int now,int L,int R,int D)
{
pushdown(now);
if (L<=tree[now].l && R>=tree[now].r)
{tree[now].sum+=D*tree[now].size; tree[now].tag+=D; return;}
int mid=(tree[now].l+tree[now].r)>>;
if (L<=mid) change(now<<,L,R,D);
if (mid<R) change(now<<|,L,R,D);
update(now);
}
int query(int now,int L,int R)
{
pushdown(now);
if (L<=tree[now].l && R>=tree[now].r) return tree[now].sum;
int mid=(tree[now].l+tree[now].r)>>,ans=;
if (L<=mid) ans+=query(now<<,L,R);
if (mid<R) ans+=query(now<<|,L,R);
// printf("%d\n",ans); puts("OK");
return ans;
}
//
struct Linenode
{
int u,v;
bool operator < (const Linenode & A) const
{return u<A.u;}
}line[maxn]; int ln;
void AddLine(int x,int y)
{
ln++;line[ln].u=x;line[ln].v=y;
}
void GetLine(int x,int y)
{
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
AddLine(pl[top[x]],pl[x]);
x=fa[top[x]];
}
if (deep[x]>deep[y]) swap(x,y);
AddLine(pl[x],pl[y]);
}
void Ask()
{
sort(line+,line+ln+);
int L=line[].u,R=line[].v,ans=;
for (int i=; i<=ln; i++)
if (line[i].u>R) ans+=query(,L,R),L=line[i].u,R=line[i].v;
else R=max(R,line[i].v);
ans+=query(,L,R);
printf("%d\n",ans&);
}
//
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
n=read();
for (int u,v,i=; i<=n-; i++) u=read(),v=read(),insert(u,v);
dfs_1(); dfs_2(,); build(,,sz);
// for (int i=1; i<=n; i++) printf("%d %d %d %d %d\n",i,pl[i],pr[i],top[i],son[i]);
q=read();
for (int i=; i<=q; i++)
{
int opt=read(),a,b,k;
if (opt==) {a=read(),b=read(),change(,pl[a],pr[a],b);continue;}
ln=; k=read();
for (int j=; j<=k; j++)
a=read(),b=read(),GetLine(a,b);
Ask();
}
return ;
}
一个智障的Interesting的故事:调了2h+的题,一直WA,后来发现提交时一直忘关文件,于是妥A了.....Let's ORZ YveH
【BZOJ-3589】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)的更多相关文章
- BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector
题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...
- dfs序+主席树 或者 树链剖分+主席树(没写) 或者 线段树套线段树 或者 线段树套splay 或者 线段树套树状数组 bzoj 4448
4448: [Scoi2015]情报传递 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 588 Solved: 308[Submit][Status ...
- BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
- BZOJ 2243:染色(树链剖分+区间合并线段树)
[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认 ...
- BZOJ 3589 动态树 (树链剖分+线段树)
前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...
- BZOJ 3589: 动态树 树链剖分+线段树+树链的并
利用树剖序的一些性质~ 这个题可以出到 $\sum k=10^5$ 左右. 做法很简单:每次暴力跳重链,并在线段树上查询链和. 查询之后打一个标记,把加过的链都置为 $0$.这样的话在同一次询问时即使 ...
- LOJ2269 [SDOI2017] 切树游戏 【FWT】【动态DP】【树链剖分】【线段树】
题目分析: 好题.本来是一道好的非套路题,但是不凑巧的是当年有一位国家集训队员正好介绍了这个算法. 首先考虑静态的情况.这个的DP方程非常容易写出来. 接着可以注意到对于异或结果的计数可以看成一个FW ...
- BZOJ 3589 动态树 树链拆分+纳入和排除定理
标题效果:鉴于一棵树.每个节点有一个右值,所有节点正确启动值他们是0.有两种操作模式,0 x y代表x右所有点的子树的根值添加y. 1 k a1 b1 a2 b2 --ak bk代表质疑. 共同拥有者 ...
- 【树链剖分(区间线段树)】BZOJ4196-[NOI2015]软件包管理
[题目大意] 如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B.同时,如果想要卸载软件包B,则必须卸载软件包A.而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会 ...
- HDU 5029 Relief grain 树链剖分打标记 线段树区间最大值
Relief grain Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid= ...
随机推荐
- 在C#中将String转换成Enum:
一: 在C#中将String转换成Enum: object Enum.Parse(System.Type enumType, string value, bool ignoreCase); 所以,我 ...
- BZOJ 1191 【HNOI2006】 超级英雄Hero
Description 现在电视台有一种节目叫做超级英雄,大概的流程就是每位选手到台上回答主持人的几个问题,然后根据回答问题的多少获得不同数目的奖品或奖金.主持人问题准备了若干道题目,只有当选手正确回 ...
- UML类图归纳
作为一个程序员,掌握UML类图是开发和阅读程序的基础. 转载请注明地址http://www.cnblogs.com/zrtqsk/p/3739288.html,谢谢! 一.基本介绍 UML是一种标准的 ...
- XmlSpy / XSD 以及 验证
很早以前看过一句话:“XML就象空气”,在企业应用开发中XML是一个重要的数据交换标准.而XSD则可以用来校验XML的数据格式是否正确. 一个典型的XSD文件如下: <?xml version= ...
- 扩展 easyui 控件系列:为datagrid 增加过滤行
此功能还为真正完成,起到抛砖引玉的效果,发动大家的力量把这个功能完善起来,效果图如下: 基本上就是扩展了 datagrid.view 中的onAfterRender 这个事件,具体代码如下: $.ex ...
- Autofac中的属性注入功能使用
使用依赖注入容器时,大部分都是使用构造函数来注入或者是xml配置文件.也有很多支持属性注入.Autofac就是其中一个. 1 为什么要有属性注入? 对于一些使用特频繁的类或者方法,很多类都会用到,那么 ...
- C语言复习(1)
test.c #include <stdio.h> int main(){ printf("hello\n"); return 0; } 1.预处理阶段 由于在test ...
- JavaScript的attribute和property辨析
1.Attribute Attribute是HTML上设置的属性,在html中显式地设置,或者通过setAttribute()方法设置. <input type='text' id='txt' ...
- HoloLens开发手记 - 测试 Testing
测试HoloLens应用的做法和测试Windows应用很类似.所有常规的内容都应该被考虑在内(功能.互操作性.性能.安全性.可靠性等等),然而有些特性是HoloLens特有的,在PC或者手机上无法测试 ...
- express+session实现简易身份认证
本文摘录自<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 文章概览 本文基于express.express-session ...