【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= ...
随机推荐
- 自定义JS常用方法
1,获取表格中的元素,支持IE,chrome,firefox //获取表单元素的某一个值 function getTableColumnValue(tableId, rowNumber, column ...
- Mysql导出函数、存储过程
下面是导出存储过程的代码 1 # mysqldump -u 数据库用户名 -p -n -t -d -R 数据库名 > 文件名 其中,-d 表示--no-create-db, -n表示--no-d ...
- zabbix-proxy3.0.4编译安装
数据库配置: innodb_file_per_table=1 安装mysql rpm -ivh http://dev.mysql.com/get/mysql-community-release-e ...
- Ros集成开发环境配置
参考资料: http://blog.csdn.net/yangziluomu/article/details/50848357 ROS使用IDE Eclipse http://blog.csdn.ne ...
- nginx学习(2):启动gzip、虚拟主机、请求转发、负载均衡
一.启用gzip gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.1; gzip_comp_level 2; ...
- java:快速文件分割及合并
文件分割与合并是一个常见需求,比如:上传大文件时,可以先分割成小块,传到服务器后,再进行合并.很多高大上的分布式文件系统(比如:google的GFS.taobao的TFS)里,也是按block为单位, ...
- 【跟着子迟品underscore】从用 `void 0` 代替 `undefined` 说起
Why underscore 最近开始看 underscore源码,并将 underscore源码解读 放在了我的 2016计划 中. 阅读一些著名框架类库的源码,就好像和一个个大师对话,你会学到很多 ...
- <实训|第十二天>用LVM对linux分区进行动态扩容
[root@localhost~]#序言在linux中,我们安装软件的途径一般有那些,你们知道吗?在linux中,如果你的磁盘空间不够用了,你知道如何来扩展磁盘吗?动态扩容不仅在工作中还是在其他方面都 ...
- 发布园友设计的新款博客皮肤BlueSky
园友#a为大家设计了一款“简单.纯粹,一点淡雅,一点宁静”的博客皮肤——BlueSky,欢迎您的享用!感谢#a的精心设计! 如果您有兴趣为大家设计博客皮肤,请将您设计的html/css/images文 ...
- ADO.NET 学习笔记 入门教程
本文转载自:http://www.youarebug.com/forum.php?mod=viewthread&tid=57&page=1&extra=#pid63 这是本人在 ...