专栏文章
题解:P13698 「CyOI」追忆
P13698题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @miodaaqt
- 此快照首次捕获于
- 2025/12/02 17:19 3 个月前
- 此快照最后确认于
- 2025/12/02 17:19 3 个月前

首先把值域离散化,变成 。考虑对值域分块。
对于询问,我们首先需要确认中位数在哪一块。设 表示 中有多少个数在块 内,设 表示 到根的链上有多少个点的值在块 内。对于操作 1 就是 加上 。对于操作 3 就是全局 。通过 数组我们就可以 定位到中位数所在的块。
然后我们再设 表示 中有多少个数字 。我们需要做的操作有:链加,全局 ,单点查。通过树上差分我们转化成:单点加,全局 ,子树(区间)查。用分块可以做到单次修改 ,单次查询 。
定位到中位数所在的块后,在块内从小往大一个一个扫就可以确定中位数。
总时间复杂度 。
CPP#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rof(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
const int Maxn=2e5,B=400;
int n,m,val[Maxn+5],h[Maxn+5],rk[Maxn+5];
int fa[Maxn+5],dep[Maxn+5],dfn[Maxn+5],siz[Maxn+5],cur;
int st[Maxn+5][20],cnt[Maxn+5][B+5]; ll all[Maxn+5],dxv;
int L[Maxn+5],R[Maxn+5],dx[Maxn+5],tot;
vector<int> v[Maxn+5];
struct DS
{
ll t[Maxn+5],sum[Maxn+5],tag[Maxn+5],pr[Maxn+5],sp[Maxn+5];
inline void push_down(int x) {For(i,L[x],R[x]) t[i]*=tag[x]; sum[x]*=tag[x],tag[x]=1;}
inline void Add(int x,ll k)
{
int id=dx[x],l=L[id]; if(tag[id]!=1) push_down(id);
t[x]+=k,sum[id]+=k; pr[l]=t[l]; For(i,l+1,R[id]) pr[i]=pr[i-1]+t[i];
For(i,1,tot) sp[i]=sp[i-1]+sum[i]*tag[i];
}
inline ll Get(int x)
{
if(x==0) return 0ll; int id=dx[x];
return sp[id-1]+pr[x]*tag[id];
}
inline ll Get(int l,int r) {return Get(r)-Get(l-1);}
} D;
inline void dfs(int x,int f)
{
fa[x]=f,dep[x]=dep[f]+1,siz[x]=1,dfn[x]=++cur,st[dfn[x]][0]=f;
for(auto y:v[x]) if(y!=f) dfs(y,x),siz[x]+=siz[y];
}
inline int GetMin(int x,int y) {return dfn[x]<dfn[y]?x:y;}
inline int LCA(int x,int y)
{
if(x==y) return x; if((x=dfn[x])>(y=dfn[y])) swap(x,y);
int len=__lg(y-x++); return GetMin(st[x][len],st[y-(1<<len)+1][len]);
}
inline void dfs2(int x,int f)
{
memcpy(cnt[x],cnt[f],sizeof(cnt[x])),cnt[x][dx[h[x]]]++;
for(auto y:v[x]) if(y!=f) dfs2(y,x);
}
inline void Init()
{
cin>>n; For(i,1,n) cin>>val[i];
iota(rk+1,rk+n+1,1);
sort(rk+1,rk+n+1,[&](int a,int b){return val[a]<val[b];});
For(i,1,n) h[rk[i]]=i;
For(i,1,n-1)
{
int a,b; cin>>a>>b;
v[a].push_back(b),v[b].push_back(a);
}
dfs(1,0); For(j,1,19) for(int i=1;i+(1<<j)-1<=n;++i)
st[i][j]=GetMin(st[i][j-1],st[i+(1<<j-1)][j-1]);
cin>>m;
for(int i=1;i<=n;i+=B)
{
++tot,L[tot]=i,R[tot]=min(i+B-1,n);
For(j,L[tot],R[tot]) dx[j]=tot;
}
dfs2(1,0);
For(i,1,tot) D.tag[i]=1;
}
inline void Modify(int x,int y,int k)
{
int z=LCA(x,y);
D.Add(dfn[x],k),D.Add(dfn[y],k),D.Add(dfn[z],-k);
if(fa[z]) D.Add(dfn[fa[z]],-k);
For(i,1,tot)
{
int res=cnt[x][i]+cnt[y][i]-cnt[z][i]-cnt[fa[z]][i];
all[i]+=1ll*res*k;
} dxv+=1ll*k*(dep[x]+dep[y]-2*dep[z]+1);
}
inline ll Get(int x) {return D.Get(dfn[x],dfn[x]+siz[x]-1);}
inline int Count()
{
ll px=(dxv+1)/2; int id=0;
For(i,1,tot) {if(px>all[i]) px-=all[i]; else {id=i; break;}}
For(i,L[id],R[id])
{
ll res=Get(rk[i]);
if(px>res) px-=res; else return i;
} return 0;
}
int main()
{
Init();
while(m--)
{
int op,x,y,k; cin>>op;
if(op==1) {cin>>x>>y>>k; Modify(x,y,k);}
if(op==2) {printf("%d\n",val[rk[Count()]]);}
if(op==3)
{
For(i,1,tot) D.tag[i]*=2,D.sp[i]*=2;
For(i,1,tot) all[i]*=2; dxv*=2;
}
}
return 0;
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...