题目传送门

题意:求树上路径可修改的第k大值是多少。

题解:CDQ整体二分+树刨。

每一个位置上的数都会有一段持续区间

根据CDQ拆的思维,可以将这个数拆成出现的时间点和消失的时间点。

然后通过整体二分第k大思路 + 树炮询问路径上出现点的个数就好了。

说一下整体二分的思路。

先假设第k大的值是mid, 然后按照时间顺序,出现一个数<=mid标记这个数的位置为1, 消失一个数<=mid,标记这个数的位置为0。

然后对于询问来说,询问路径上的值, 与 k进行比较, 如果 值 >= k则说明这个询问的第k大落在区间[ l, mid]之间, 否则落在 [mid+1,r]之间,并且第k大是在[mid+1,r] 的 k -= 路劲值。

然后将所有 修改且值 <= mid 和 询问第k大落在左边的 询问放到 数组的左边, 其他放到数组的右边, 然后递归下去处理左边 / 右边的这个区间。

这样每个操作最多只会访问lg次。

每次操作的复杂度是lg*lg。

所以最后的复杂度是n*lg^3.

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fop freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod = (int)1e9+;
const int N = 8e5 + ;
const int M = * N;
int head[N], to[M], nt[M];
int sz[N], son[N], deep[N], top[N], fa[N], dfn[N], dto[N], tr[N<<];
int tot, dtot;
int n;
int a[N];
struct Node{
int k, a, b, id;
}A[M], B[M], C[M];
/**
k == -1 Add -> pos[a] = b
k == -2 Del -> pos[a] = 0
else k Query with ans[id]
**/
void add(int u, int v){
to[tot] = v; nt[tot] = head[u]; head[u] = tot++; to[tot] = u; nt[tot] = head[v]; head[v] = tot++;
}
void dfs1(int o, int u){
sz[u] = ;
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(v == o) continue;
dfs1(u, v);
if(sz[v] > sz[son[u]]) son[u] = v;
sz[u] += sz[v];
}
}
void dfs2(int o, int u, int t){
deep[u] = deep[o] + ;
top[u] = t;
fa[u] = o;
dfn[u] = ++dtot;
dto[dtot] = u;
if(son[u]) dfs2(u, son[u], t);
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(v == o || v == son[u]) continue;
dfs2(u, v, v);
}
}
void PushUp(int rt){
tr[rt] = tr[rt<<] + tr[rt<<|];
}
int Query(int L, int R, int l, int r, int rt){
if(L <= l && r <= R)
return tr[rt];
int m = l+r >> ;
int ret = ;
if(L <= m) ret += Query(L, R, lson);
if(m < R) ret += Query(L, R, rson);
return ret;
}
void Updata(int L, int C, int l, int r, int rt){
if(l == r){
tr[rt] = C;
return ;
}
int m = l+r >> ;
if(L <= m) Updata(L, C, lson);
else Updata(L, C, rson);
PushUp(rt);
return ;
}
int Query_Path(int x, int y){
int fx = top[x], fy = top[y];
int ret = ;
while(fx != fy){
if(deep[fx] > deep[fy]){
ret += Query(dfn[fx],dfn[x],,n,);
x = fa[fx]; fx = top[x];
}
else {
ret += Query(dfn[fy],dfn[y],,n,);
y = fa[fy]; fy = top[y];
}
}
if(deep[x] < deep[y]) ret += Query(dfn[x], dfn[y], , n, );
else ret += Query(dfn[y], dfn[x], , n,);
return ret;
}
int lca(int x, int y){
int fx = top[x], fy = top[y];
while(fx != fy){
if(deep[fx] > deep[fy])
x = fa[fx]; fx = top[x];
else
y = fa[fy]; fy = top[y];
}
if(deep[x] < deep[y]) return x;
return y;
}
void init(){
memset(head, -, sizeof(head));
memset(son, , sizeof son);
tot = dtot = ;
}
int atot = ;
void AddNode(int op, int a, int b, int id){
A[++atot] = {op, a, b, id};
}
int ans[N];
void cdq(int ansl, int ansr, int l, int r){
if(l > r) return ;
if(ansl == ansr){
for(int i = l; i <= r; ++i)
if(A[i].id)
ans[A[i].id] = ansl;
return ;
}
int mid = ansl+ansr >> ;
int tb = , tc = ;
for(int i = l; i <= r; ++i){
if(A[i].k == -){
if(A[i].b <= mid){
B[++tb] = A[i];
Updata(dfn[A[i].a], , , n, );
}
else {
C[++tc] = A[i];
}
}
else if(A[i].k == -){
if(A[i].b <= mid){
B[++tb] = A[i];
Updata(dfn[A[i].a], , , n, );
}
else
C[++tc] = A[i];
}
else {
int kk = Query_Path(A[i].a, A[i].b);
if(kk >= A[i].k)
B[++tb] = A[i];
else
A[i].k -= kk;
C[++tc] = A[i];
}
}
for(int i = ; i <= tb; ++i)
A[i+l-] = B[i];
for(int i = ; i <= tc; ++i)
A[tb+l+i-] = C[i];
cdq(ansl, mid, l, tb+l-);
cdq(mid+, ansr, tb+l, r);
}
int main(){
init();
int q;
scanf("%d%d", &n, &q);
for(int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
AddNode(-, i, a[i], );
}
int x, y;
for(int i = ; i < n; ++i) {
scanf("%d%d", &x, &y);
add(x, y);
}
int m = ;
dfs1(,);
dfs2(,,);
int k;
for(int i = ; i <= q; ++i){
scanf("%d%d%d", &k, &x, &y);
if(k) {
int z = lca(x,y);
z = deep[x] + deep[y] - deep[z] * + ;
if(z < k){
ans[++m] = -;
}
else AddNode(z-k+, x, y, ++m);
}
else {
AddNode(-, x, a[x], );
AddNode(-, x, y, );
a[x] = y;
}
}
for(int i = ; i <= n; ++i)
AddNode(-, i, a[i], )
cdq(, 1e8+, , atot);
for(int i = ; i <= m; ++i)
if(~ans[i]) printf("%d\n", ans[i]);
else puts("invalid request!");
return ;
}

bzoj 1146 网络管理Network (CDQ 整体二分 + 树刨)的更多相关文章

  1. 2019.01.13 bzoj1146: [CTSC2008]网络管理Network(整体二分+树剖)

    传送门 题意简述:给一棵树,支持单点修改,询问路径上两点间第kkk大值. 思路: 读懂题之后立马可以想到序列上带修区间kkk大数的整体二分做法,就是用一个bitbitbit来支持查值. 那么这个题把树 ...

  2. bzoj 2738: 矩阵乘法【整体二分+树状数组】

    脑子一抽开始写主席树,敲了一会发现不对-- 整体二分,用二维树状数组维护值为当前区间的格子个数,然后根据k的大小和当前询问的子矩阵里的值和k的大小关系来决定这个询问放在哪一部分向下递归 #includ ...

  3. [CTSC2008]网络管理(整体二分+树剖+树状数组)

    一道经典的带修改树链第 \(k\) 大的问题. 我只想出三个 \(\log\) 的解法... 整体二分+树剖+树状数组. 那不是暴力随便踩的吗??? 不过跑得挺快的. \(Code\ Below:\) ...

  4. 【BZOJ-2527】Meteors 整体二分 + 树状数组

    2527: [Poi2011]Meteors Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 831  Solved: 306[Submit][Stat ...

  5. 【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询

    Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位 ...

  6. BZOJ_3110_[Zjoi2013]K大数查询_整体二分+树状数组

    BZOJ_3110_[Zjoi2013]K大数查询_整体二分+树状数组 Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位 ...

  7. 【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改

    题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数 ...

  8. 【bzoj4009】[HNOI2015]接水果 DFS序+树上倍增+整体二分+树状数组

    题目描述 给出一棵n个点的树,给定m条路径,每条路径有一个权值.q次询问求一个路径包含的所有给定路径中权值第k小的. 输入 第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数. 接下来n ...

  9. 【bzoj2527】[Poi2011]Meteors 整体二分+树状数组

    题目描述 有N个成员国.现在它发现了一颗新的星球,这颗星球的轨道被分为M份(第M份和第1份相邻),第i份上有第Ai个国家的太空站. 这个星球经常会下陨石雨.BIU已经预测了接下来K场陨石雨的情况.BI ...

随机推荐

  1. 解决微信小程序开发者工具输入框焦点问题

    Windows10笔记本上运行微信小程序开发者工具,输入框(input,textarea)没有焦点,只能在真机调试,效率太低.后来发现是Window10对笔记本高分屏支持不好,要DPI缩放,导致兼容性 ...

  2. Zabbix利用Windows性能监视器监控各项资源指标

    zabbix自带的windows监控模板并没有监控windows cpu使用率的监控 在cmd命令输入perfmon 打开后默认就一项CPU占用的监控,下面以添加硬盘空闲时间做示例 1:监控图形上面右 ...

  3. 数据结构-二叉搜索树和二叉树排序算法(python实现)

    今天我们要介绍的是一种特殊的二叉树--二叉搜索树,同时我们也会讲到一种排序算法--二叉树排序算法.这两者之间有什么联系呢,我们一起来看一下吧. 开始之前呢,我们先来介绍一下如何创建一颗二叉搜索树. 假 ...

  4. java虚拟机学习笔记(五)---运行时的数据区域

    Java虚拟机所管理的内存包括以下几个运行时的数据区域:方法区,堆,虚拟机栈,本地方法栈,程序计数器.下面对其进行介绍: 程序计数器 它是一块较小的内存空间,可以看做当前线程做执行的字节码的信号指示器 ...

  5. java并发编程(十八)----(线程池)java线程池框架Fork-Join

    还记得我们在初始介绍线程池的时候提到了Executor框架的体系,到现在为止我们只有一个没有介绍,与ThreadPoolExecutor一样继承与AbstractExecutorService的For ...

  6. 牛客多校训练第八场C.CDMA(思维+构造)

    题目传送门 题意: 输入整数m( m∈2k ∣ k=1,2,⋯,10),构造一个由1和-1组成的m×m矩阵,要求对于任意两个不同的行的内积为0. 题解: Code: #include<bits/ ...

  7. Amazon S3

    Amazon S3 是什么? Amazon S3 是亚马逊推出的一款存储服务,名为 Amazon Simple Storage Service,即亚马逊简单存储服务. 有些 S3 的概念需要了解一下: ...

  8. 从SpringBoot构建十万博文聊聊缓存穿透

    前言 在博客系统中,为了提升响应速度,加入了 Redis 缓存,把文章主键 ID 作为 key 值去缓存查询,如果不存在对应的 value,就去数据库中查找 .这个时候,如果请求的并发量很大,就会对后 ...

  9. JWT+Interceptor实现无状态登录和鉴权

    无状态登录原理 先提一下啥是有状态登录 单台tomcat的情况下:编码的流程如下 前端提交表单里用户的输入的账号密码 后台接受,查数据库, 在数据库中找到用户的信息后,把用户的信息存放到session ...

  10. 02、安装Linux系统

    1.我们打开VM软件,然后点击“创建新的虚拟机”,选择“经典”选项 2.选中“稍后安装操作系统”单选按钮,然后单击“下一步”按钮 3.将客户机操作系统的类型选择为“Linux”,版本为"Re ...