题解:[Ynoi2011] ODT

题目传送门

题意分析

维护链上信息,显然可以树链剖分做到 \(\mathcal O\left(\log n^2\right)\) 修改。

但是需要查询 \(x\) 的子节点、自己、父节点点权第 \(k\) 小。

延续树剖的思路,将重子节点单独处理,数据结构维护轻子节点点权。

这样修改的时候只需要修改链顶 \(\textit{top}_x\) 的父节点 \(\textit{father}_{\textit{top}_x}\) 维护信息即可,这一部分信息单次修改 \(\mathcal O(\log n)\) 次。

数据结构维护第 \(k\) 小,显然可以使用平衡树。

时间复杂度 \(\mathcal O\left(m\log^2n\right)\)


但是平衡树可能会被卡常,注意到子节点的数量其实并不多(除非是数据卡这种),因此可以使用 vector 维护单调序列,单次插入 \(\mathcal O(n)\)

时间复杂度 \(\mathcal O(mn\log n)\),但是跑不满,可过。

AC 代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=1e6;
int n,a[N+1];
vector<int>g[N+1];
struct BST{
	vector<int>t;
	void erase(int x){
		t.erase(lower_bound(t.begin(),t.end(),x));
	}
	void insert(int x){
		t.insert(upper_bound(t.begin(),t.end(),x),x);
	}
	int kth_element(int k){
		return t[k-1];
	}
}bst[N+1];
namespace hld{
	int father[N+1],depth[N+1],size[N+1],son[N+1];
	void dfs1(int x,int fx){
		father[x]=fx;
		size[x]=1;
		depth[x]=depth[fx]+1;
		for(int i:g[x]){
			if(i==fx){
				continue;
			}
			dfs1(i,x);
			size[x]+=size[i];
			if(size[i]>size[son[x]]){
				son[x]=i;
			}
		}
	}
	int top[N+1],dfn[N+1],rnk[N+1];
	void dfs2(int x,int topx){
		top[x]=topx;
		static int cnt;
		dfn[x]=++cnt;
		rnk[cnt]=x;
		if(son[x]){
			dfs2(son[x],topx);
		}
		for(int i:g[x]){
			if(i==father[x]||i==son[x]){
				continue;
			}
			dfs2(i,i);
			bst[x].insert(a[i]);
		}
	}
	struct segTree{
		struct node{
			int l,r;
			int value,tag;
		}t[N<<2|1];
		
		int size(int p){
			return t[p].r-t[p].l+1;
		}
		void up(int p){
			t[p].value=t[p<<1].value+t[p<<1|1].value;
		}
		void build(int p,int l,int r){
			t[p]={l,r};
			if(l==r){
				t[p].value=a[rnk[l]];
				return;
			}
			int mid=l+r>>1;
			build(p<<1,l,mid);
			build(p<<1|1,mid+1,r);
			up(p);
		}
		void down(int p){
			if(t[p].tag){
				t[p<<1].value+=size(p<<1)*t[p].tag;
				t[p<<1].tag+=t[p].tag;
				t[p<<1|1].value+=size(p<<1|1)*t[p].tag;
				t[p<<1|1].tag+=t[p].tag;
				t[p].tag=0;
			}
		}
		void add(int p,int l,int r,int k){
			if(l<=t[p].l&&t[p].r<=r){
				t[p].value+=size(p)*k;
				t[p].tag+=k;
				return;
			}
			down(p);
			if(l<=t[p<<1].r){
				add(p<<1,l,r,k);
			}
			if(t[p<<1|1].l<=r){
				add(p<<1|1,l,r,k);
			}
			up(p);
		}
		int query(int p,int l,int r){
			if(l<=t[p].l&&t[p].r<=r){
				return t[p].value;
			}
			down(p);
			int ans=0;
			if(l<=t[p<<1].r){
				ans+=query(p<<1,l,r);
			}
			if(t[p<<1|1].l<=r){
				ans+=query(p<<1|1,l,r);
			}
			return ans;
		}
	}t;
	int main(){
		dfs1(1,0);
		dfs2(1,1);
		t.build(1,1,n);
		return 0;
	}
	void add(int u,int v,int k){
		while(top[u]!=top[v]){
			if(depth[top[u]]<depth[top[v]]){
				swap(u,v);
			}
			bst[father[top[u]]].erase(t.query(1,dfn[top[u]],dfn[top[u]]));
			t.add(1,dfn[top[u]],dfn[u],k);
			bst[father[top[u]]].insert(t.query(1,dfn[top[u]],dfn[top[u]]));
			u=father[top[u]];
		}
		if(dfn[u]>dfn[v]){
			swap(u,v);
		}
		if(u==top[u]&&father[u]){
			bst[father[u]].erase(t.query(1,dfn[u],dfn[u]));
		}
		t.add(1,dfn[u],dfn[v],k);
		if(u==top[u]&&father[u]){
			bst[father[u]].insert(t.query(1,dfn[u],dfn[u]));
		}
	}
	int query(int x,int k){
		int plX=t.query(1,dfn[x],dfn[x]),plFather,plSon;
		if(father[x]){
			plFather=t.query(1,dfn[father[x]],dfn[father[x]]);
		}
		if(son[x]){
			plSon=t.query(1,dfn[son[x]],dfn[son[x]]);
		}
		bst[x].insert(plX);
		if(father[x]){
			bst[x].insert(plFather);
		}
		if(son[x]){
			bst[x].insert(plSon);
		} 
//		for(int i:bst[x].t){
//			cerr<<i<<' '; 
//		}
//		cerr<<endl;
		int ans=bst[x].kth_element(k);
		bst[x].erase(plX);
		if(father[x]){
			bst[x].erase(plFather);
		}
		if(son[x]){
			bst[x].erase(plSon);
		}
		return ans;
	}
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	int m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	hld::main();
	while(m--){
		int op,x,y,z;
		cin>>op>>x>>y;
		if(op==1){
			cin>>z;
			hld::add(x,y,z);
		}else{
			cout<<hld::query(x,y)<<'\n';
		}
	}	
	
	cout.flush();
	 
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
/*
5 2
3 4 3 1 3
1 2
1 3
2 4
3 5
1 1 1 1
2 1 3

4
*/
posted @ 2025-08-10 23:09  TH911  阅读(9)  评论(0)    收藏  举报