P5314 ODT(毒瘤树剖)

题面

题目描述

给你一棵树,边权为 111,有点权。

需要支持两个操作:

  • 1 x y z:表示把树上 xxx 到 yyy 这条简单路径的所有点点权都加上 zzz。
  • 2 x y:表示查询与点 xxx 距离小于等于 111 的所有点里面的第 yyy 小点权。

输入格式

第一行两个整数 n,mn,mn,m。

第二行 nnn 个整数表示每个点的点权。

之后 n−1n-1n−1 行,每行两个整数 x,yx,yx,y 表示 xxx 和 yyy 之间连有一条边。

之后 mmm 行,每行为 1 x y z 或者 2 x y 形式,意义如上述。

输出格式

对每个 2 操作输出一行,每行一个整数表示答案。

数据保证每次询问都存在答案。

输入输出样例 #1

输入 #1

复制代码
5 5
3 4 3 1 3
1 2
1 3
2 4
3 5
2 1 3
2 1 1
1 1 1 1
2 1 3
1 4 1 1

输出 #1

复制代码
4
3
4

说明/提示

subtask 1:20%20\%20% n,m≤1000n,m\leq 1000n,m≤1000。

subtask 2:10%10\%10% 树为一条链。

subtask 3:20%20\%20% n,m≤105n,m\leq 10^5n,m≤105。

subtask 4:30%30\%30% n,m≤4×105n,m\leq 4\times 10^5n,m≤4×105。

subtask 5:20%20\%20% n,m≤106n,m\leq 10^6n,m≤106。

对于 100%100\%100% 的数据,1≤n,m≤1061\leq n,m\leq 10^61≤n,m≤106,0\\leq 每次加的数 ≤2000\leq 2000≤2000,0\\leq 初始的点权 ≤2000\leq 2000≤2000。

题解

opt1

看到这题,对于树上操作,我想到树剖 ,操作1显然树剖 后用线段树 / 树状数组+差分维护每个点的值

opt2

看到

2 x y:表示查询与点 xxx 距离小于等于 111 的所有点里面的 第 yyy 小点权

显然可以用平衡树 去维护第y小

考虑有哪些点会影响答案,可见只有父节点重儿子轻儿子集合 还有它本身 ,那么我们对于每一个节点建一颗平衡树去维护答案

考虑在修改之后会有什么影响,由于树链剖分的性质,一条链上的修改顶多改log(n)次 ,而每个点只有一个重儿子 ,在查询的时候加回来就行 了,没必要在平衡树上维护,用上文的树状数组维护,维护父节点、自己同理 。那么我们的平衡树就只用维护轻儿子们了

分析复杂度,暴力修改有树状数组的O(log⁡n)+树剖修改轻儿子跳链的O(log⁡n)∗平衡树的O(logn)O(\log n)+树剖修改轻儿子跳链的O(\log n)*平衡树的O(logn)O(logn)+树剖修改轻儿子跳链的O(logn)∗平衡树的O(logn)为O(log⁡2n)O(\log^2 n)O(log2n)

查询就是一个单老哥

整个时间复杂度O(qlog⁡2n)O(q\log^2 n)O(qlog2n)好悬

代码:

cpp 复制代码
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
int n,m,r,cnt;
vector<int> e[1000001];
int son[1000001],top[1000001],fa[1000001],id[1000001];
int dep[1000001],siz[1000001];
int w[1000001],res;
struct node{
	int u,id;
	bool operator<(const node& y)const{
		return u!=y.u?u<y.u:id<y.id;
	}
};
int lowbit(int x){
	return x&(-x);
}
tree<node ,null_type,less<node>,rb_tree_tag,tree_order_statistics_node_update> tr[1000001];
struct shuzu{
	int tr[1000003];
	void add(int x,int y){
		for(int i=x;i<=n;i+=lowbit(i)){
			tr[i]+=y;
		}
	}
	int cha(int x){
		int sum=0;
		for(int i=x;i>=1;i-=lowbit(i)){
			sum+=tr[i];
		}
		return sum;
	}
	void addqu(int x,int y,int c){
		add(x,c);
		add(y+1,-c);
	}
}tre;
void dfs1(int u,int f,int deep){
	dep[u]=deep;
	fa[u]=f;
	siz[u]=1;
	int maxson=-1;
	for(int i:e[u]){
		if(i==f){
			continue;
		}
		dfs1(i,u,deep+1);
		siz[u]+=siz[i];
		if(siz[i]>maxson){
			son[u]=i;
			maxson=siz[i];
		}
	}
}
void dfs2(int u,int topf){
	id[u]=++cnt;
	tre.addqu(cnt,cnt,w[u]);
	top[u]=topf;
	if(!son[u]){
		return ;
	}
	dfs2(son[u],topf);
	for(int i:e[u]){
		if(i==fa[u]||i==son[u]){
			continue;
		}
		tr[u].insert({w[i],i});
		dfs2(i,i);
	}
}
void treeadd(int x,int y,int c){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]){
			swap(x,y);
		}
		int tp=top[x],now=x;
		x=fa[top[x]];
		tr[x].erase({w[tp],tp});
		tre.addqu(id[tp],id[now],c);
		w[tp]=tre.cha(id[tp]);
		tr[x].insert({w[tp],tp});
	}
	if(dep[x]<dep[y]){
		swap(x,y);
	}
	tre.addqu(id[y],id[x],c);
	if(top[y]!=y||!fa[y]){
		return ;
	}
	tr[fa[y]].erase({w[y],y});
	w[y]=tre.cha(id[y]);
	tr[fa[y]].insert({w[y],y});
}
void join(int u,int s){
	if(s)tr[u].insert({tre.cha(id[s]),s});
}
void del(int u,int s){
	if(s)tr[u].erase({tre.cha(id[s]),s});
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>w[i];
	}
	for(int i=1;i<n;i++){
		int x,y;
		cin>>x>>y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
//	cout<<"OK"<<endl;
	dfs1(1,0,1);
	dfs2(1,1);
	while(m--){
		int opt,x,y,z;
		cin>>opt>>x>>y;
		if(opt==1){
			cin>>z;
			treeadd(x,y,z);
		}
		else{
			join(x,x);
			join(x,son[x]);
			join(x,fa[x]);
			cout<<tr[x].find_by_order(y-1)->u<<"\n";
			del(x,x);
			del(x,son[x]);
			del(x,fa[x]);
		}
	}
}

本篇题解与封面没有任何关系,这题解不是五彩斑斓的世界

相关推荐
CHANG_THE_WORLD1 小时前
深入指针5:回调函数与泛型排序
数据结构·算法
qq_454245031 小时前
计算机与AI领域中的“上下文”:多维度解析
数据结构·人工智能·分类
Once_day1 小时前
GCC编译(4)构造和析构函数
c语言·c++·编译和链接
今儿敲了吗1 小时前
24| 字符串
数据结构·c++·笔记·学习·算法
橘色的喵1 小时前
嵌入式 Telnet 调试 Shell 重构: 纯 POSIX 轻量化实现
c++
橘色的喵1 小时前
ztask: 一个C++14编写的、 类型安全、RAII 与模板化任务调度器
c++
Wect1 小时前
LeetCode 105. 从前序与中序遍历序列构造二叉树:题解与思路解析
前端·算法·typescript
小雨中_1 小时前
2.5 动态规划方法
人工智能·python·深度学习·算法·动态规划
小龙报1 小时前
【51单片机】不止是调光!51 单片机 PWM 实战:呼吸灯 + 直流电机正反转 + 转速控制
数据结构·c++·stm32·单片机·嵌入式硬件·物联网·51单片机