BZOJ 3589: 动态树 树链剖分+线段树+树链的并
利用树剖序的一些性质~
这个题可以出到 $\sum k=10^5$ 左右.
做法很简单:每次暴力跳重链,并在线段树上查询链和.
查询之后打一个标记,把加过的链都置为 $0$.
这样的话在同一次询问时即使有重复的也无所谓.
然后本次查询后在线段树的 $1$ 号节点再打一个标记,用来将那些置零的标记清空.
这个主要是利用树剖序的连续性质.
具体细节还是需要注意一下.
Code:
#include <cstdio>
#include <algorithm>
#define N 200004
#define ll long long
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)
using namespace std;
const ll mod=2147483648;
void Add(ll &g,ll b)
{
g=(g+b)%mod;
}
namespace seg
{
struct Node
{
int tag,mark;
ll sum,sumvir,add;
}t[N<<2];
void mark_tag(int now)
{
t[now].mark=1,t[now].tag=0,t[now].sum=t[now].sumvir;
}
void mark_add(int l,int r,int now,ll v)
{
Add(t[now].add,v), Add(t[now].sumvir,(r-l+1)*v%mod);
if(t[now].tag) t[now].sum=0;
else t[now].sum=t[now].sumvir;
}
void pushdown(int l,int r,int now)
{
int mid=(l+r)>>1;
if(t[now].mark)
{
if(mid>=l) mark_tag(now<<1);
if(r>mid) mark_tag(now<<1|1);
t[now].mark=0;
}
if(t[now].add)
{
if(mid>=l) mark_add(l,mid,now<<1,t[now].add);
if(r>mid) mark_add(mid+1,r,now<<1|1,t[now].add);
t[now].add=0;
}
}
void pushup(int l,int r,int now)
{
int mid=(l+r)>>1;
t[now].sum=t[now].sumvir=0;
if(mid>=l) Add(t[now].sum,t[now<<1].sum),Add(t[now].sumvir,t[now<<1].sumvir);
if(r>mid) Add(t[now].sum,t[now<<1|1].sum),Add(t[now].sumvir,t[now<<1|1].sumvir);
if(t[now].tag) t[now].sum=0;
}
void update_tag(int l,int r,int now,int L,int R)
{
if(l>=L&&r<=R)
{
t[now].tag=1,t[now].sum=t[now].mark=0;
return;
}
pushdown(l,r,now);
int mid=(l+r)>>1;
if(L<=mid) update_tag(l,mid,now<<1,L,R);
if(R>mid) update_tag(mid+1,r,now<<1|1,L,R);
pushup(l,r,now);
}
void update_add(int l,int r,int now,int L,int R,ll v)
{
if(l>=L&&r<=R)
{
mark_add(l,r,now,v);
return;
}
pushdown(l,r,now);
int mid=(l+r)>>1;
if(L<=mid) update_add(l,mid,now<<1,L,R,v);
if(R>mid) update_add(mid+1,r,now<<1|1,L,R,v);
pushup(l,r,now);
}
ll query(int l,int r,int now,int L,int R)
{
if((l>=L&&r<=R)||(t[now].tag)) return t[now].sum;
int mid=(l+r)>>1;
pushdown(l,r,now);
ll re=0;
if(L<=mid) Add(re,query(l,mid,now<<1,L,R));
if(R>mid) Add(re,query(mid+1,r,now<<1|1,L,R));
return re;
}
};
int n,Q,edges,tim;
int hd[N],to[N<<1],nex[N<<1],val[N];
int size[N],son[N],top[N],dfn[N],fa[N],dep[N],st[N],ed[N];
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void dfs1(int u,int ff)
{
fa[u]=ff,dep[u]=dep[ff]+1,size[u]=1;
for(int i=hd[u];i;i=nex[i])
if(to[i]!=ff)
{
dfs1(to[i],u),size[u]+=size[to[i]];
if(size[to[i]]>size[son[u]]) son[u]=to[i];
}
}
void dfs2(int u,int tp)
{
top[u]=tp,st[u]=dfn[u]=++tim;
if(son[u]) dfs2(son[u],tp);
for(int i=hd[u];i;i=nex[i])
if(to[i]!=fa[u]&&to[i]!=son[u]) dfs2(to[i],to[i]);
ed[u]=tim;
}
ll work(int x,int y)
{
ll re=0;
while(top[x]!=top[y])
{
if(dep[top[y]]>dep[top[x]]) swap(x,y);
Add(re,seg::query(1,n,1,dfn[top[x]],dfn[x]));
seg::update_tag(1,n,1,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
Add(re,seg::query(1,n,1,dfn[y],dfn[x]));
seg::update_tag(1,n,1,dfn[y],dfn[x]);
return re;
}
int main()
{
int i,j;
// setIO("input");
scanf("%d",&n);
for(i=1;i<n;++i)
{
int u,v;
scanf("%d%d",&u,&v),add(u,v),add(v,u);
}
dfs1(1,0),dfs2(1,1);
scanf("%d",&Q);
for(int cas=1;cas<=Q;++cas)
{
int opt;
scanf("%d",&opt);
if(opt==0)
{
int u;
ll v;
scanf("%d%lld",&u,&v);
seg::update_add(1,n,1,st[u],ed[u],v);
}
if(opt==1)
{
ll ans=0;
int k,u,v;
scanf("%d",&k);
for(i=1;i<=k;++i) scanf("%d%d",&u,&v), Add(ans,work(u,v));
seg::mark_tag(1);
printf("%lld\n",ans);
}
}
return 0;
}
BZOJ 3589: 动态树 树链剖分+线段树+树链的并的更多相关文章
- BZOJ 3589 动态树 (树链剖分+线段树)
前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...
- BZOJ 3531 SDOI2014 旅行 树链剖分+线段树动态开点
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3531 题意概述: 给出一棵N个点的树,树上的每个结点有一个颜色和权值,支持以下四种操作: ...
- BZOJ.1758.[WC2010]重建计划(分数规划 点分治 单调队列/长链剖分 线段树)
题目链接 BZOJ 洛谷 点分治 单调队列: 二分答案,然后判断是否存在一条长度在\([L,R]\)的路径满足权值和非负.可以点分治. 对于(距当前根节点)深度为\(d\)的一条路径,可以用其它子树深 ...
- 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp
题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...
- 【bzoj4712】洪水 树链剖分+线段树维护树形动态dp
题目描述 给出一棵树,点有点权.多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值. 输入 输入文件第一行包含 ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- P3313 [SDOI2014]旅行——树链剖分+线段树(动态开点?)
P3313 [SDOI2014]旅行 一棵树,其中的点分类,点有权值,在一条链上找到一类点中的最大值或总和: 树链剖分把树变成链: 把每个宗教单开一个线段树,维护区间总和和最大值: 宗教很多,需要动态 ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点
题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...
随机推荐
- 厉害了,ES 如何做到几十亿数据检索 3 秒返回!
一.前言 数据平台已迭代三个版本,从头开始遇到很多常见的难题,终于有片段时间整理一些已完善的文档,在此分享以供所需朋友的 实现参考,少走些弯路,在此篇幅中偏重于ES的优化,关于HBase,Hadoop ...
- Java第七周课堂示例总结
一.super();调用基类构造方法 代码: class Grandparent{ public Grandparent(){ System.out.println("GrandParent ...
- LOJ526「LibreOJ β Round #4」子集
题目 算是比较裸的题吧. 首先我们把符合要求的\((i,j)\)建一条边,那么我们要求的就是最大团. 转化为补图的最小独立集. 然后我们来证明补图是一个二分图. \((u,v)\)有边\(\Leftr ...
- python __dict__ 跟 dir()的区别
__dict__:要是对象的话返回的是一个对象自身的实例属性.不包括类的属性:要是类的__dict__则不包括父类的属性,只包含自身类属性[方法.类变量],不包括实例属性.正是这样.每个实例的实例属性 ...
- 滚动页面产生动画WOW.js的用法
简介 在一些网页上,当你滚动页面的时候会看到各式各样的元素动画效果,非常动感.WOW.js 就是一款帮助你实现这种 CSS 动画效果的插件.WOW.js 依赖 animate.css,所以它支持 an ...
- Windows Runtime (RT)
学了sl for wp 开发了1年都没入门,只能说自己的学习欲望太低了. 今天偶然才发现wrt 跟 .net 是2个东西... orz. 得抛弃 sl ,wrt才是未来的主流吧... 这篇文章不错 h ...
- Dasha and Photos CodeForces - 761F (前缀优化)
大意: 给定n*m初始字符矩阵, 有k个新矩阵, 第$i$个矩阵是由初始矩阵区间赋值得到的, 求选择一个新矩阵, 使得其余新矩阵到它距离和最小. 字符集比较小, 可以考虑每次区间覆盖对每个字符的贡献. ...
- Java 父类的static成员在子类中的继承情况
父类的static成员在子类中的继承状况是怎么样的呢? 昨天突然想到这个问题,刚才试验了一下,发现很容易解释,没什么值得探讨的. 首先在学习继承时,书本都没有强调static成员有什么特殊的地方. 然 ...
- 多列表zip合并的csv持久化储存
有时xpath爬取数据之后会返回多个列表,这些列表的长度一样,这时候可以用zip()合并,然后返回一个zip对象,直接传入储存函数,进行持久化储存 例如: name=['张三','李四','王五'] ...
- centos查看实时网络带宽占用情况方法【转】
Linux中查看网卡流量工具有iptraf.iftop以及nethogs等,iftop可以用来监控网卡的实时流量(可以指定网段).反向解析IP.显示端口信息等. centos安装iftop的命令如下: ...