有一棵 个点的树,每个点上有一个二叉搜索树。
然后依次进行 次操作:
1 u v x
:在 路径上每个点的二叉搜索树中插入元素 ,即 执行 :void insert(int&p,int x){ if(!p) return p=x,void(); if(x<p) insert(ch[p][0],x); else insert(ch[p][1],x); }
0 u w
:在点 上的二叉搜索树中执行 ,求其返回值:long long ask(int p,int x){ if(x==p) return x; if(x<p) return ch[p][0]?ask(ch[p][0])+p:p; else return ch[p][1]?ask(ch[p][1])+p:p; }
,每次 操作的 互不相同。
先考虑单点怎么做,直接维护二叉搜索树中每个点的父亲即可,一个点 的父亲是其插入时前驱和后继中插入时间较晚的那个。
接下来考虑链,一个朴素的想法是差分,问题变为维护加入/删除某次操作后二叉搜索树的形态。
使用超强注意力,用二元组 记录点 的插入时间是 ,那么注意到 的点和 的点是独立的。具体的,对于 的点,可以这样判断它们中哪些是 的祖先:
- 将这些点按照 从大到小排序;
- 令 ,依次遍历排好序后的每个点 :
- 若 则其为 祖先,答案加上 ,令 ;
- 否则其非 祖先;
对于 的点是一样的,将从大到小排序改为从小到大排序即可。
那么问题转化为区间中 的前缀/后缀最小值的 的和,直接楼房重建线段树即可 维护。
现在考虑树,不难发现和链是基本一样的,线段树合并即可。
时间复杂度 ,代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
/*
insert/delete pot
query [l,r] premin sum or sufmin sum
*/
namespace seg
{
const int TS=30000005,inf=1e8;
int cnt,ls[TS],rs[TS];
int mn[TS];
ll sml[TS],smr[TS];
inline void init(){mn[0]=inf;}
ll quesml(int u,int l,int r,int k) // premin(<k) sum
{
if(u==0||mn[u]>=k) return 0;
if(l==r) return mn[u]<k?sml[u]:0;
int mid=l+r>>1;
if(mn[ls[u]]<k) return quesml(ls[u],l,mid,k)+sml[u]-sml[ls[u]];
else return quesml(rs[u],mid+1,r,k);
}
ll quesmr(int u,int l,int r,int k) // sufmin(<k) sum
{
if(u==0||mn[u]>=k) return 0;
if(l==r) return mn[u]<k?smr[u]:0;
int mid=l+r>>1;
if(mn[rs[u]]<k) return smr[u]-smr[rs[u]]+quesmr(rs[u],mid+1,r,k);
else return quesmr(ls[u],l,mid,k);
}
inline void upda(int u,int l,int r)
{
int mid=l+r>>1;
int sl=ls[u],sr=rs[u];
mn[u]=min(mn[sl],mn[sr]);
sml[u]=sml[sl]+quesml(sr,mid+1,r,mn[sl]);
smr[u]=quesmr(sl,l,mid,mn[sr])+smr[sr];
}
void updp(int &u,int l,int r,int p,int x,int val)
{
if(u==0) u=++cnt;
if(l==r) return mn[u]=x,sml[u]=smr[u]=val,void();
int mid=l+r>>1;
if(p<=mid) updp(ls[u],l,mid,p,x,val);
else updp(rs[u],mid+1,r,p,x,val);
upda(u,l,r);
}
int merge(int x,int y,int l,int r)
{
if(x==0||y==0) return x+y;
if(l==r)
{
mn[x]=min(mn[x],mn[y]);
sml[x]=max(sml[x],sml[y]);
smr[x]=sml[x];
return x;
}
int mid=l+r>>1;
ls[x]=merge(ls[x],ls[y],l,mid);
rs[x]=merge(rs[x],rs[y],mid+1,r);
upda(x,l,r);
return x;
}
void quesmllr(int u,int l,int r,int L,int R,int &k,ll &res)
{
if(u==0||l>R||r<L) return;
if(l>=L&&r<=R)
{
res+=quesml(u,l,r,k);
k=min(k,mn[u]);
return;
}
int mid=l+r>>1;
if(L<=mid) quesmllr(ls[u],l,mid,L,R,k,res);
if(R>=mid+1) quesmllr(rs[u],mid+1,r,L,R,k,res);
}
void quesmrlr(int u,int l,int r,int L,int R,int &k,ll &res)
{
if(u==0||l>R||r<L) return;
if(l>=L&&r<=R)
{
res+=quesmr(u,l,r,k);
k=min(k,mn[u]);
return;
}
int mid=l+r>>1;
if(R>=mid+1) quesmrlr(rs[u],mid+1,r,L,R,k,res);
if(L<=mid) quesmrlr(ls[u],l,mid,L,R,k,res);
}
}
const int S=200005,BS=25;
int n,m;
vector<int> g[S];
int dep[S],fat[S][BS];
vector<pair<int,int> > vec[S];
int tot,b[S],val[S],rt[S];
ll ans[S];
void dfs(int u,int fa)
{
dep[u]=dep[fa]+1;
fat[u][0]=fa;
for(int i=1;i<=BS-3;i++) fat[u][i]=fat[fat[u][i-1]][i-1];
for(int v:g[u]) if(v!=fa) dfs(v,u);
}
inline int quelca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=BS-3;i>=0;i--) if(dep[fat[x][i]]>=dep[y]) x=fat[x][i];
if(x==y) return x;
for(int i=BS-3;i>=0;i--)
{
if(fat[x][i]!=fat[y][i])
{
x=fat[x][i];
y=fat[y][i];
}
}
return fat[x][0];
}
void dfs2(int u,int fa)
{
for(int v:g[u])
{
if(v==fa) continue;
dfs2(v,u);
rt[u]=seg::merge(rt[u],rt[v],1,tot);
}
for(auto t:vec[u])
{
int x=t.first,y=t.second;
if(y==-1)
{
int k=x;
seg::quesmrlr(rt[u],1,tot,1,val[x],k,ans[x]);
k=x;
seg::quesmllr(rt[u],1,tot,val[x],tot,k,ans[x]);
k=x;
ll del=0;
seg::quesmllr(rt[u],1,tot,val[x],val[x],k,del);
ans[x]-=del;
}
else
{
if(x==1) seg::updp(rt[u],1,tot,val[y],y,b[val[y]]);
else seg::updp(rt[u],1,tot,val[y],seg::inf,0);
}
}
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n-1;i++)
{
int x,y;
cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1,0);
vector<int> queid;
for(int i=1;i<=m;i++)
{
int op,x,y;
cin>>op>>x>>y;
if(op==1)
{
int w;
cin>>w;
int l=quelca(x,y);
vec[x].emplace_back(1,i);
vec[y].emplace_back(1,i);
vec[fat[l][0]].emplace_back(-1,i);
b[++tot]=val[i]=w;
}
else
{
vec[x].emplace_back(i,-1);
b[++tot]=val[i]=y;
queid.push_back(i);
}
}
sort(b+1,b+tot+1);
tot=unique(b+1,b+tot+1)-b-1;
for(int i=1;i<=m;i++) val[i]=lower_bound(b+1,b+tot+1,val[i])-b;
seg::init();
dfs2(1,0);
for(int x:queid) cout<<ans[x]<<'\n';
return 0;
}