不知道为什么要把这两个没什么关系的算法放到一起写...可能是都很黑科技?

1.线段树分治

例题:bzoj4026 二分图

给你一个图,资瓷加一条边,删一条边,询问当前图是不是二分图

如果用 LCT 的话我们要维护关于删除时间的最大生成树,然后每进来一条边判断奇环,就很难写

线段树分治可以很好的解决这种有插入有删除单点询问的问题

如果没有加入边和删除边的操作,显然我们可以用带权并查集判断奇环解决

然后我们就要考虑怎么把带加入和带删除的问题转换成没有加入和删除的问题

我们记一下每条边存在的时间区间,把这些时间区间放到线段树上

对于线段树的每一个区间,我们加入时间区间正好完全包含这个区间的边,判断有没有奇环

有奇环,这一段全都是 No ,没有奇环,我们递归到左右区间分别判断

如果递归到了 $l == r$ 也就是一个时间的单点,还没有奇环的话,这个单点就是 Yes

中间判断奇环的部分,一个节点所用到的边是它和它所有祖先的边,所以处理完一个区间要把多余的边删掉

这个可以用按秩合并的可撤销并查集,这个并查集还要维护每个点到根节点距离的奇偶性

这样做的好处是,把带插入带删除的问题,转换成了没有插入没有删除的 sb 题

复杂度的话,就是一个线段树区间修改 + 整体询问的复杂度

所以是 $O(nlogn)$ 的

#include<bits/stdc++.h>
#define LL long long
#define SET vector<edge>
using namespace std;
const int maxn = 2e5 + ; inline int read()
{
int x = ,f = ;char ch = getchar();
for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
for(;isdigit(ch);x = * x + ch - '',ch = getchar());
return x * f;
}
int n,m,T;
struct edge
{
int u,v,l,r;
bool operator < (const edge &b)const
{
if(l == b.l) return r < b.r;
return l < b.l;
}
};
SET S;
int top = ;
namespace ufsufs
{
struct node{int fa,val,size;}t[maxn];
struct info{int x,y;node a,b;}st[maxn];
inline void init(){for(int i=;i<=n;i++) t[i] = (node){i, , };}
inline int find(int x){while(t[x].fa != x) x = t[x].fa;return x;}
inline int dis(int x)
{
int ret = ;
for(;t[x].fa != x;x = t[x].fa)ret ^= t[x].val;
return ret;
}
inline void link(int x,int y)
{
int val = dis(x) ^ dis(y) ^ ;
x = find(x),y = find(y);
st[++top] = (info){x,y,t[x],t[y]};
if(t[x].size > t[y].size)swap(x,y);
t[x].fa = y;t[x].val = val;t[y].size += t[x].size;
}
inline void rec(int bot)
{
while(top != bot)
{
info &now = st[top--];
t[now.x] = now.a;t[now.y] = now.b;
}
}
}
using namespace ufsufs;
inline void SegDiv(int l,int r,SET &S)
{
int mid = (l + r) >> ,bot = top;
SET ls,rs;
for(int i=;i<(int)S.size();i++)
{
edge &now = S[i];
int x = now.u,y = now.v;
if(now.l == l && now.r == r)
{
int fx = find(x),fy = find(y);
if(fx == fy)
{
int val = dis(x) ^ dis(y);
if(!val)
{
for(int i=l;i<=r;i++)puts("No");
rec(bot);return;
}
}
else link(x,y);
}
else if(now.r <= mid)ls.push_back(now);
else if(now.l > mid)rs.push_back(now);
else ls.push_back( (edge){now.u, now.v, now.l, mid} ), rs.push_back( (edge){now.u, now.v, mid+, now.r} );
}
if(l == r)puts("Yes");
else SegDiv(l,mid,ls),SegDiv(mid + ,r,rs);
rec(bot);
} int main()
{
n = read(),m = read(),T = read();
for(int i=;i<=m;i++)
{
int u = read(),v = read(),l = read() + ,r = read();
if(l > r)continue;
S.push_back((edge){u,v,l,r});
}
init();
SegDiv(,T,S);
}

其他的一些题

wzj 的两道题 paint & route

bzoj4137 火星商店问题   可持久化 Trie 树 + 线段树分治

loj121 动态图连通性(离线可过)  可撤销并查集 + 线段树分治

2.动态dp

引入 1 :有 n 个矩阵,q 次操作,支持单矩阵内元素修改,区间查询矩阵乘积

sol:因为矩阵乘法有结合律,可以用线段树维护这 n 个矩阵,相当于单点修改,区间查询

引入 2:有一个 dp (原谅我实在想不到啥正经的 dp 能满足这个)每一步的转移关于点权都是线性齐次的,且每步转移一样,每一次单点修改一个点的点权,修改后询问 dp 的答案

sol:因为线性齐次而且每步一样,我们可以用矩阵加速这个 dp,然后变成了上一道题

引入 3 :树上最大点权独立集,q 次操作,支持修改一个点的点权,以及询问答案

sol:这就有点难了

先考虑不带修改

定义 $f_{(u,0/1)}$ 为 $u$ 点选 / 不选,它的子树内最大点权独立集的点权和

转移就是

$f_{(u,0)} = \sum_{v∈son[u]}max(f_{(v,0)},f_{(v,1)})$

$f_{(u,1)} = \sum_{v∈son[u]}f_{(v,0)} + val_u$

然后我们发现,只要知道一个子树里的所有 $f$ 值,它的 $f$ 值也知道了

我们用 dsu on tree(我没学过 但 SCX 大神学过 好像是这样的。。。)的思想

我们每到一个点,就把它下面那条重链加到队列里,然后把和它只隔一条轻链的重链加到队列里,递归下去,等所有点都加进去之后按入队次序的倒序 dp

根据 dsu on tree(感觉过两天要学一学啊。。。),这样做和正常 dp 顺序是等价的

这样我们可以把这个 dp 转化一下

维护一个 light_dp 和 heavy_dp

根据树链剖分的性质,轻儿子必定是重链链头,所以轻儿子的 lightdp 和 heavydp 都算完了

$lightdp_{(u,0)} = \sum_{v∈lightson[u]}max(heavydp_{(u,0)},heavydp_{(u,1)})$

$lightdp_{(u,1)} = \sum_{v∈lightson[u]}heavydp_{(u,0)}$

$heavydp_{(u,0)} = lightdp_{(u,0)} + max(heavydp_{(u,1)},heavydp_{(u,0)})$

$heavydp_{(u,1)} = lightdp_{(u,1)} + heavydp_{(u,0)}$

这样我们就把树上的 dp 转换成了链上的 dp,然后变成了上一道题

具体地,我们树链剖分,每个点维护一个转移矩阵,然后用线段树快速维护一条重链的 dp 值

这样我们修改到一个点,它重链链头的 heavydp 就会改变,相当于线段树的区间修改

然后这个重链链头的父亲的 lightdp 会因为它而改变,相当于线段树的单点修改

我们套用上一题的做法就可以了

修改就是相当于修改一个点到根的 dp 值,根据树链剖分是 $O(nlog^2n)$ 的

[基本操作]线段树分治和动态dp的更多相关文章

  1. 【bzoj4712】洪水 树链剖分+线段树维护树形动态dp

    题目描述 给出一棵树,点有点权.多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值. 输入 输入文件第一行包含 ...

  2. [HDU4867]Xor (线段树分治+类数位dp)

    [HDU4867]Xor (线段树分治+类数位dp) 提供一种\((m+n) log a log m\)带有常数约\(\frac{1}{log n}\)的算法 处理询问,将后来加入的数算进序列中,则每 ...

  3. LOJ 121 「离线可过」动态图连通性——LCT维护删除时间最大生成树 / 线段树分治

    题目:https://loj.ac/problem/121 离线,LCT维护删除时间最大生成树即可.注意没有被删的边的删除时间是 m+1 . 回收删掉的边的节点的话,空间就可以只开 n*2 了. #i ...

  4. LOJ#121. 「离线可过」动态图连通性(线段树分治)

    题意 板子题,题意很清楚吧.. Sol 很显然可以直接上LCT.. 但是这题允许离线,于是就有了一个非常巧妙的离线的做法,好像叫什么线段树分治?? 此题中每条边出现的位置都可以看做是一段区间. 我们用 ...

  5. P3206 [HNOI2010]城市建设 [线段树分治+LCT维护动态MST]

    Problem 这题呢 就边权会在某一时刻变掉-众所周知LCT不支持删边的qwq- 所以考虑线段树分治- 直接码一发 如果 R+1 这个时间修改 那就当做 [L,R] 插入了一条边- 然后删的边和加的 ...

  6. 4712: 洪水 基于链分治的动态DP

    国际惯例的题面:看起来很神的样子......如果我说这是动态DP的板子题你敢信?基于链分治的动态DP?说人话,就是树链剖分线段树维护DP.既然是DP,那就先得有转移方程.我们令f[i]表示让i子树中的 ...

  7. 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)

    [BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...

  8. LOJ 2585 「APIO2018」新家 ——线段树分治+二分答案

    题目:https://loj.ac/problem/2585 算答案的时候要二分! 这样的话,就是对于询问位置 x ,二分出一个最小的 mid 使得 [ x-mid , x+mid ] 里包含所有种类 ...

  9. 【CF938G】Shortest Path Queries(线段树分治,并查集,线性基)

    [CF938G]Shortest Path Queries(线段树分治,并查集,线性基) 题面 CF 洛谷 题解 吼题啊. 对于每个边,我们用一个\(map\)维护它出现的时间, 发现询问单点,边的出 ...

随机推荐

  1. android 自定义 listView

    目录: 1.主布局 ListView <?xml version="1.0" encoding="utf-8"?><RelativeLayou ...

  2. CSS3 --添加阴影(盒子阴影、文本阴影的使用)

     CSS3 - 给div或者文字添加阴影(盒子阴影.文本阴影的使用)CSS3定义了两种阴影:盒子阴影和文本阴影.其中盒子阴影需要IE9及其更新版本,而文本阴影需要IE10及其更新版本.下面分别介绍两种 ...

  3. android shape的用法总结

    参考代码: <shape xmlns:android="http://schemas.android.com/apk/res/android" > <corner ...

  4. 自己定义Application的未捕获异常处理

    近期由于工作原因.进行Android应用开发时发现应用在出现类似空指针等异常时,抛出未被捕获的异常.Android系统有默认的未捕获异常处理器,默认行为是结束对应的线程,但并不会直接退出程序,并且在应 ...

  5. Linux 服务器上建立用户并分配权限

    查看用户 whoami #要查看当前登录用户的用户名 who am i #表示打开当前伪终端的用户的用户名 who mom likes who 命令其它常用参数 参数 说明 -a 打印能打印的全部 - ...

  6. 在VS2017环境中编译libxml2库

    libxml2库编译 1.下载libxml2,官网是:http://www.xmlsoft.org/downloads.html, 我下载的版本是:libxml2-sources-2.9.7.tar. ...

  7. python爬虫之Selenium

    Selenium的使用 #!/usr/bin/env python # -*- coding:utf-8 -*- """ Selenium是一个第三方模块,可以完全模拟用 ...

  8. CodeBackUP_node_find_serial

    /*************************************************************** ** Find the serial number Node ** R ...

  9. 用linux搭建ranzhi环境

    一.安装红帽6.5 1.安装时需选择桥接模式: 2.选择自定义,在设置中将镜像文件(ISO)选择进去: 3.安装时选择[桌面]安装(在/etc/inittab文件中,若id=5则为桌面模式,id=3为 ...

  10. 【Flask】filter 常用查询条件

    1. equal    2. not equal  3. like, ilike  4.in  5. not in 6. is null  7. is not null  8. and  9. or ...