3589: 动态树

Time Limit: 30 Sec  Memory Limit: 1024 MB
Submit: 405  Solved: 137
[Submit][Status][Discuss]

Description

别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件
事件0:
这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子.
事件1:
小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次.

Input

第一行一个整数n(1<=n<=200,000), 即节点数.
接下来n-1行, 每行两个数字u, v. 表示果子u和果子v之间有一条直接的边. 节点从1开始编号.
在接下来一个整数nQ(1<=nQ<=200,000), 表示事件.
最后nQ行, 每行开头要么是0, 要么是1.
如果是0, 表示这个事件是事件0. 这行接下来的2个整数u, delta表示以u为根的子树中的每个节点长出了delta个果子.
如果是1, 表示这个事件是事件1. 这行接下来一个整数K(1<=K<=5), 表示这次询问涉及K个树枝. 接下来K对整数u_k, v_k, 每个树枝从节点u_k到节点v_k. 由于果子数可能非常多, 请输出这个数模2^31的结果.

Output

对于每个事件1, 输出询问的果子数.

Sample Input

5
1 2
2 3
2 4
1 5
3
0 1 1
0 2 3
1 2 3 1 1 4

Sample Output

13

HINT

1 <= n <= 200,000, 1 <= nQ <= 200,000, K = 5.

生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.

Source

By 佚名提供

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】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)的更多相关文章

  1. BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...

  2. dfs序+主席树 或者 树链剖分+主席树(没写) 或者 线段树套线段树 或者 线段树套splay 或者 线段树套树状数组 bzoj 4448

    4448: [Scoi2015]情报传递 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 588  Solved: 308[Submit][Status ...

  3. BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  4. BZOJ 2243:染色(树链剖分+区间合并线段树)

    [SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认 ...

  5. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  6. BZOJ 3589: 动态树 树链剖分+线段树+树链的并

    利用树剖序的一些性质~ 这个题可以出到 $\sum k=10^5$ 左右. 做法很简单:每次暴力跳重链,并在线段树上查询链和. 查询之后打一个标记,把加过的链都置为 $0$.这样的话在同一次询问时即使 ...

  7. LOJ2269 [SDOI2017] 切树游戏 【FWT】【动态DP】【树链剖分】【线段树】

    题目分析: 好题.本来是一道好的非套路题,但是不凑巧的是当年有一位国家集训队员正好介绍了这个算法. 首先考虑静态的情况.这个的DP方程非常容易写出来. 接着可以注意到对于异或结果的计数可以看成一个FW ...

  8. BZOJ 3589 动态树 树链拆分+纳入和排除定理

    标题效果:鉴于一棵树.每个节点有一个右值,所有节点正确启动值他们是0.有两种操作模式,0 x y代表x右所有点的子树的根值添加y. 1 k a1 b1 a2 b2 --ak bk代表质疑. 共同拥有者 ...

  9. 【树链剖分(区间线段树)】BZOJ4196-[NOI2015]软件包管理

    [题目大意] 如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B.同时,如果想要卸载软件包B,则必须卸载软件包A.而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会 ...

  10. HDU 5029 Relief grain 树链剖分打标记 线段树区间最大值

    Relief grain Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid= ...

随机推荐

  1. C语言操作文件

    #include <stdio.h> struct stu{ ]; int num; int age; ]; }boya[],boyb[]; struct stu *pa,*pb; mai ...

  2. 苹果IOS开发者账号总结--发布应用APP时team name是否可以随意写?

    个人账号(Individual): 费用99美金一年, 该账号在App Store销售者只能显示个人的ID,比如zhitian zhang,单人使用.个人账号只能有一个开发者.100个苹果的iOS设备 ...

  3. QuartzCore笔记

    Quartz Core 图层编程 一.添加 Quartz Core 框架 要使用 Quartz Core 框架,你需要将其添加到你的工程中 . 然后 #import <Quartz Core/Q ...

  4. Windows 8.1 新增控件之 Hyperlink

    Hyperlink 控件应该不用过多介绍大家肯定十分清楚其作用,它的功能就像HTML中的<a href="">标签一样,只不过是在XAML中实现. 使用Hyperlin ...

  5. office2016各个版本 以及 解决visio搜索任何都提示无匹配项问题

    http://tieba.baidu.com/p/4089747196 版本:Office 2016 Visio 专业版 32位版文件名:SW_DVD5_Visio_Pro_2016_W32_ChnS ...

  6. 如何让jboss eap 6.2+ 的多个war应用共享 jar 包?

    weblogic有一个很贴心的功能,允许把多个war应用共同依赖的jar包,打包一个单独的war,以libary方式部署,然后各应用在weblogic.xml里声明引用该libary即可,这样可大大减 ...

  7. Caffe学习系列(23):如何将别人训练好的model用到自己的数据上

    caffe团队用imagenet图片进行训练,迭代30多万次,训练出来一个model.这个model将图片分为1000类,应该是目前为止最好的图片分类model了. 假设我现在有一些自己的图片想进行分 ...

  8. Apache Shiro 使用手册(一)Shiro架构介绍 - kdboy - ITeye技术网站

    转载 原文地址 http://kdboy.iteye.com/blog/1154644 一.什么是Shiro Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理 ...

  9. 【LeetCode】95. Unique Binary Search Trees II

    Unique Binary Search Trees II Given n, generate all structurally unique BST's (binary search trees) ...

  10. java 客户端链接不上redis解决方案

    原文地址:http://blog.csdn.net/yingxiake/article/details/51472810 出现问题描述: 1.Could not get a resource from ...