【题目链接】

点击打开链接

【算法】

树链剖分

对于线段树的每个节点,记录这段区间的最小值,最小值的个数,值为0的个数,此外,还要维护两个懒惰标记

【代码】

本题细节很多,写程序时要认真严谨!

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define MAXLOG 20
const int INF = 1e9; int i,n,m,tot,opt,u,v,c,x,y,timer,Lca,tmp;
int dep[MAXN],dfn[MAXN],head[MAXN],size[MAXN],anc[MAXN][MAXLOG],fa[MAXN],top[MAXN],son[MAXN]; struct Edge
{
int to,nxt;
} e[MAXN<<]; struct SegmentTree
{
struct Node
{
int l,r,sum,cnt,Min,taga,tagb;
} Tree[MAXN<<];
inline void build(int index,int l,int r)
{
int mid;
Tree[index].l = l; Tree[index].r = r;
Tree[index].sum = Tree[index].cnt = r - l + ;
Tree[index].taga = -;
Tree[index].tagb = ;
Tree[index].Min = ;
if (l == r) return;
mid = (l + r) >> ;
build(index<<,l,mid);
build(index<<|,mid+,r);
}
inline void pushdown(int index)
{
int l = Tree[index].l,r = Tree[index].r;
int mid = (l + r) >> ;
if (Tree[index].taga != -)
{
Tree[index<<].sum = mid - l + ;
if (!Tree[index].taga) Tree[index<<].cnt = mid - l + ;
else Tree[index<<].cnt = ;
Tree[index<<].Min = Tree[index].taga;
Tree[index<<|].sum = r - mid;
if (!Tree[index].taga) Tree[index<<|].cnt = r - mid;
else Tree[index<<|].cnt = ;
Tree[index<<|].Min = Tree[index].taga;
Tree[index<<].tagb = Tree[index<<|].tagb = ;
Tree[index<<].taga = Tree[index<<|].taga = Tree[index].taga;
Tree[index].taga = -;
}
if (Tree[index].tagb)
{
Tree[index<<].Min += Tree[index].tagb;
if (!Tree[index<<].Min) Tree[index<<].cnt = Tree[index<<].sum;
else Tree[index<<].cnt = ;
Tree[index<<|].Min += Tree[index].tagb;
if (!Tree[index<<|].Min) Tree[index<<|].cnt = Tree[index<<|].sum;
else Tree[index<<|].cnt = ;
if (Tree[index<<].taga != -) Tree[index<<].taga += Tree[index].tagb;
else Tree[index<<].tagb += Tree[index].tagb;
if (Tree[index<<|].taga != -) Tree[index<<|].taga += Tree[index].tagb;
else Tree[index<<|].tagb += Tree[index].tagb;
Tree[index].tagb = ;
}
}
inline void update(int index)
{
Tree[index].Min = min(Tree[index<<].Min,Tree[index<<|].Min);
Tree[index].cnt = Tree[index<<].cnt + Tree[index<<|].cnt;
if (Tree[index<<].Min < Tree[index<<|].Min) Tree[index].sum = Tree[index<<].sum;
else if (Tree[index<<|].Min < Tree[index<<].Min) Tree[index].sum = Tree[index<<|].sum;
else Tree[index].sum = Tree[index<<].sum + Tree[index<<|].sum;
}
inline void modify(int index,int l,int r,int val)
{
int mid;
if (l > r) return;
if (Tree[index].l == l && Tree[index].r == r)
{
Tree[index].Min = val;
Tree[index].taga = val;
Tree[index].tagb = ;
Tree[index].sum = r - l + ;
if (!val) Tree[index].cnt = r - l + ;
else Tree[index].cnt = ;
return;
}
pushdown(index);
mid = (Tree[index].l + Tree[index].r) >> ;
if (mid >= r) modify(index<<,l,r,val);
else if (mid + <= l) modify(index<<|,l,r,val);
else
{
modify(index<<,l,mid,val);
modify(index<<|,mid+,r,val);
}
update(index);
}
inline void add(int index,int l,int r,int val)
{
int mid;
if (l > r) return;
if (Tree[index].l == l && Tree[index].r == r)
{
Tree[index].Min += val;
if (Tree[index].taga != -) Tree[index].taga += val;
else Tree[index].tagb += val;
if (!Tree[index].Min) Tree[index].cnt = Tree[index].sum;
else Tree[index].cnt = ;
return;
}
pushdown(index);
mid = (Tree[index].l + Tree[index].r) >> ;
if (mid >= r) add(index<<,l,r,val);
else if (mid + <= l) add(index<<|,l,r,val);
else
{
add(index<<,l,mid,val);
add(index<<|,mid+,r,val);
}
update(index);
}
inline int query_min(int index,int l,int r)
{
int mid;
if (l > r) return INF;
if (Tree[index].l == l && Tree[index].r == r) return Tree[index].Min;
pushdown(index);
mid = (Tree[index].l + Tree[index].r) >> ;
if (mid >= r) return query_min(index<<,l,r);
else if (mid + <= l) return query_min(index<<|,l,r);
else return min(query_min(index<<,l,mid),query_min(index<<|,mid+,r));
}
inline int query()
{
return Tree[].cnt - ;
}
} T;
inline void add(int u,int v)
{
tot++;
e[tot] = (Edge){v,head[u]};
head[u] = tot;
}
inline void dfs1(int u)
{
int i,v;
size[u] = ;
anc[u][] = fa[u];
for (i = ; i < MAXLOG; i++)
{
if (dep[u] < ( << i)) break;
anc[u][i] = anc[anc[u][i-]][i-];
}
for (i = head[u]; i; i = e[i].nxt)
{
v = e[i].to;
if (fa[u] != v)
{
dep[v] = dep[u] + ;
fa[v] = u;
dfs1(v);
size[u] += size[v];
if (size[v] > size[son[u]]) son[u] = v;
}
}
}
inline void dfs2(int u,int tp)
{
int i,v;
dfn[u] = ++timer;
top[u] = tp;
if (son[u]) dfs2(son[u],tp);
for (i = head[u]; i; i = e[i].nxt)
{
v = e[i].to;
if (fa[u] != v && son[u] != v) dfs2(v,v);
}
}
inline void solve1(int u,int v,int c)
{
int tu = top[u],tv = top[v];
while (tu != tv)
{
T.modify(,dfn[tv],dfn[v],c);
v = fa[tv]; tv = top[v];
}
T.modify(,dfn[u]+,dfn[v],c);
}
inline void solve2(int u,int v,int c)
{
int tu = top[u],tv = top[v];
while (tu != tv)
{
T.add(,dfn[tv],dfn[v],c);
v = fa[tv]; tv = top[v];
}
T.add(,dfn[u]+,dfn[v],c);
}
inline int query_min(int u,int v)
{
int tu = top[u],tv = top[v],ans = INF;
while (tu != tv)
{
ans = min(ans,T.query_min(,dfn[tv],dfn[v]));
v = fa[tv]; tv = top[v];
}
ans = min(ans,T.query_min(,dfn[u]+,dfn[v]));
return ans;
}
inline int lca(int x,int y)
{
int i,t;
if (dep[x] > dep[y]) swap(x,y);
t = dep[y] - dep[x];
for (i = ; i < MAXLOG; i++)
{
if (t & ( << i))
y = anc[y][i];
}
if (x == y) return x;
for (i = MAXLOG - ; i >= ; i--)
{
if (anc[x][i] != anc[y][i])
{
x = anc[x][i];
y = anc[y][i];
}
}
return fa[x];
}
template <typename T> inline void read(T &x)
{
int f = ; x = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; }
for (; isdigit(c); c = getchar()) x = (x << ) + (x << ) + c - '';
x *= f;
}
template <typename T> inline void write(T x)
{
if (x < )
{
putchar('-');
x = -x;
}
if (x > ) write(x/);
putchar(x%+'');
}
template <typename T> inline void writeln(T x)
{
write(x);
puts("");
} int main() { read(n); read(m);
for (i = ; i < n; i++)
{
read(x); read(y);
add(x,y);
add(y,x);
}
dfs1();
dfs2(,);
T.build(,,timer);
while (m--)
{
read(opt);
if (opt == )
{
read(u); read(v); read(c);
Lca = lca(u,v);
solve1(Lca,u,c);
solve1(Lca,v,c);
} else
{
read(u); read(v); read(c);
Lca = lca(u,v);
tmp = min(query_min(Lca,u),query_min(Lca,v));
if (tmp + c < ) c = -tmp;
solve2(Lca,u,c);
solve2(Lca,v,c);
}
writeln(T.query());
} return ; }

【BZOJ 4353】 Play with tree的更多相关文章

  1. Kruskal算法及其类似原理的应用——【BZOJ 3654】tree&&【BZOJ 3624】[Apio2008]免费道路

    首先让我们来介绍Krukal算法,他是一种用来求解最小生成树问题的算法,首先把边按边权排序,然后贪心得从最小开始往大里取,只要那个边的两端点暂时还没有在一个联通块里,我们就把他相连,只要这个图里存在最 ...

  2. 【BZOJ 1150】 1150: [CTSC2007]数据备份Backup (贪心+优先队列+双向链表)

    1150: [CTSC2007]数据备份Backup Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设 ...

  3. 【BZOJ 2957】楼房重建&&Codechef COT5 Count on a Treap&&【NOIP模拟赛】Weed 线段树的分治维护

    线段树是一种作用于静态区间上的数据结构,可以高效查询连续区间和单点,类似于一种静态的分治.他最迷人的地方在于“lazy标记”,对于lazy标记一般随我们从父区间进入子区间而下传,最终给到叶子节点,但还 ...

  4. LCA 【bzoj 4281】 [ONTAK2015]Związek Harcerstwa Bajtockiego

    [bzoj 4281] [ONTAK2015]Związek Harcerstwa Bajtockiego Description 给定一棵有n个点的无根树,相邻的点之间的距离为1,一开始你位于m点. ...

  5. 【BZOJ 1191】 [Apio2010]特别行动队 (斜率优化)

    dsy1911: [Apio2010]特别行动队 [题目描述] 有n个数,分成连续的若干段,每段的分数为a*x^2+b*x+c(a,b,c是给出的常数),其中x为该段的各个数的和.求如何分才能使得各个 ...

  6. 【BZOJ 1096】 [ZJOI2007]仓库建设 (斜率优化)

    1096: [ZJOI2007]仓库建设 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3940  Solved: 1736 Description ...

  7. 【BZOJ 2132】圈地计划 && 【7.22Test】计划

    两种版本的题面 Description 最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地.据了解,这块土 ...

  8. -【线性基】【BZOJ 2460】【BZOJ 2115】【HDU 3949】

    [把三道我做过的线性基题目放在一起总结一下,代码都挺简单,主要就是贪心思想和异或的高斯消元] [然后把网上的讲解归纳一下] 1.线性基: 若干数的线性基是一组数a1,a2,a3...an,其中ax的最 ...

  9. 【BZOJ 3223】 文艺平衡树

    [题目链接] 点击打开链接 [算法] 本题是splay区间操作的模板题 我们每个点的权值设为”当前在序列中的排名“,根据二叉排序树的性质,这棵树的中序遍历就是当前序列 如果我们要获得一段区间[l,r] ...

随机推荐

  1. laravel学习笔记2--表单

    一.Controller 1.Request 1.1.取值:input // 1.取值 echo $request->input('name'); // 2.取不到值时打印默认值 echo $r ...

  2. Mysql:sql语句

    练习的表可以在博客的文件中下载 基础知识: 1.数据库的连接 mysql -u -p -h -u 用户名 -p 密码 -h host主机 2:库级知识 2.1 显示数据库: show database ...

  3. Python之文件处理-递归删除特定文件

    Python之文件处理-递归删除特定文件 #!/usr/bin/env python # -*- coding:utf-8 -*- import os def delete_particular_fi ...

  4. Vue如何点亮多个tab选项简易方法

    我们平常遇到点击选择会遇到单选或多选,当你设计图是自定义的时候,第一反应就是引入UI插件吧.可是如果项目只用到插件的这一点点功能,我们引入了一个插件这就不太友好了.此时我们自己写这个小功能是很简单的, ...

  5. java 通过反射机制调用某个类的方法

    package net.xsoftlab.baike; import java.lang.reflect.Method; public class TestReflect {     public s ...

  6. xtu summer individual-4 D - Martian Strings

    Martian Strings Time Limit: 2000ms Memory Limit: 262144KB This problem will be judged on CodeForces. ...

  7. 62. mybatis 使用PageHelper不生效【从零开始学Spring Boot】

    [从零开始学习Spirng Boot-常见异常汇总] 在Spirng Boot中集成了PageHelper,然后也在需要使用分页的地方加入了如下代码: PageHelper.startPage(1,1 ...

  8. 【BZOJ4710】分特产(容斥原理,组合计数)

    题意:有m种特产,第i种有a[i]个 有n个同学分特产,要求: 1.恰好分完 2.每个人至少要分到一个 求方案数模10^9+7 n,m,a[i]<=1000 思路:WYZ作业 首先考虑对于每一种 ...

  9. bzoj2212 Tree Rotations

    被BZOJ坑了一下午,原以为是我程序有问题一直WA,结果是我数组小了...为啥不给我RE!!! 线段树合并,对于逆序对而言,只能通过交换左右子树来达到,那么我们就可以想到对于一个结点而言,我们当然要取 ...

  10. CLR GC

    一.垃圾回收算法 每个应用程序都包含一组根(root),每个根都是一个存储位置,他要么为null,要么指向托管堆的一个对象,类型中定义的静态字段.局部变量.方法参数等都会被认为是根. 垃圾回收器(GC ...