题解:[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
*/

浙公网安备 33010602011771号