P6779 题解
wmy_goes_to_thu · · 题解
考虑分块。
注意到空间可能比较大,可以选择按块处理。
那么对于一个块,从前往后枚举询问:
遇到一个区间无交的询问,忽略
遇到一个散块询问,暴力重构这个块
遇到一个整块询问,考虑维护一个链表,因为如果它的父亲被占用了,那么它就没用了,因为都是整块跳。那么每次扫一遍链表,可以证明它的复杂度均摊是对的。
复杂度
有一些细节要注意,这里放一个不卡常的代码
#include<bits/stdc++.h>
using namespace std;
int tot=0,bg[200005],gb[200005],fa[200005],ffa[200005],sz[200005],dep[200005];
int a[200005],bl[200005],bs[1005],es[1005];
int n,m,rt,cs[1005],l1[200005],l2[200005],jt[200005],vist[200005];
int OP[200005],L[200005],R[200005],vvv[200005];
vector<pair<int,int> >g[200005];
long long dist[200005],ans[200005],ZXZ;
void dfs(int x,int la)
{
sz[x]=1;
for(int i=0;i<g[x].size();i++)
{
int cu=g[x][i].first,c2=g[x][i].second;
if(cu==la)continue;
dist[cu]=dist[x]+c2,dep[cu]=dep[x]+1;
dfs(cu,x);
sz[x]+=sz[cu],fa[cu]=x;
}
}
void dfs2(int x,int la)
{
bg[x]=++tot,gb[bg[x]]=x;
if(sz[x]==1)return;
int ans=0,w;
for(int i=0;i<g[x].size();i++)
{
int cu=g[x][i].first,c2=g[x][i].second;
if(cu==la)continue;
if(ans<sz[cu])ans=sz[cu],w=cu;
}
ffa[w]=ffa[x],dfs2(w,x);
for(int i=0;i<g[x].size();i++)
{
int cu=g[x][i].first,c2=g[x][i].second;
if(cu==la||cu==w)continue;
ffa[cu]=cu,dfs2(cu,x);
}
}
void jum(int x,int le)
{
if(!le)return;
int y=a[x];
while(ffa[y]!=rt&&le>dep[y]-dep[ffa[y]])
{
le-=dep[y]-dep[ffa[y]]+1;
y=fa[ffa[y]];
}
if(dep[y]<le)y=rt;
else y=gb[bg[y]-le];
a[x]=y;
}
void chonggou(int x,int l,int r)
{
ZXZ=LLONG_MAX;
for(int i=bs[x];i<=es[x];i++)
{
int dd=cs[x]-vvv[i];
if(l<=i&&i<=r)jum(i,dd+1);
else jum(i,dd);
ZXZ=min(ZXZ,dist[a[i]]);
}
cs[x]=0;
for(int i=bs[x];i<=es[x];i++)l1[i]=i-1,l2[i]=i+1,vvv[i]=0;
l1[bs[x]]=l2[es[x]]=0;
l1[bs[x]]=n+1,l2[n+1]=bs[x];
}
int main()
{
cin>>n>>m>>rt;
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
g[u].push_back(make_pair(v,w));
g[v].push_back(make_pair(u,w));
}
fa[rt]=rt,dfs(rt,0);
ffa[rt]=rt,dfs2(rt,0);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int S=sqrt(n+0.5),SS=(n-1)/S+1;
for(int i=1;i<SS;i++)
{
bs[i]=(i-1)*S+1,es[i]=i*S;
for(int j=bs[i];j<=es[i];j++)bl[j]=i;
}
bs[SS]=(SS-1)*S+1,es[SS]=n;
for(int j=bs[SS];j<=es[SS];j++)bl[j]=SS;
int gs=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&OP[i],&L[i],&R[i]);
if(OP[i]==2)gs++;
}
memset(ans,63,sizeof(ans));
for(int i=1;i<=SS;i++)
{
ZXZ=LLONG_MAX;
for(int j=bs[i];j<=es[i];j++)
l1[j]=j-1,l2[j]=j+1,vvv[j]=0,ZXZ=min(ZXZ,dist[a[j]]);
l1[bs[i]]=l2[es[i]]=0;
l1[bs[i]]=n+1,l2[n+1]=bs[i];
for(int j=1;j<=m;j++)
{
int op=OP[j],l=L[j],r=R[j];
if(es[i]<l||bs[i]>r)continue;
if(l<=bs[i]&&es[i]<=r)
{
if(op==2)
{
ans[j]=min(ans[j],ZXZ);
continue;
}
cs[i]++;
for(int k=l2[n+1];k;k=l2[k])
{
if(vist[fa[a[k]]]==i)
{
int pr=l1[k],nx=l2[k];
l2[pr]=nx,l1[nx]=pr;
}else
{
a[k]=fa[a[k]];
vvv[k]++;
vist[a[k]]=i;
ZXZ=min(ZXZ,dist[a[k]]);
}
}
}else
{
int ll=max(l,bs[i]),rr=min(r,es[i]);
if(op==1)chonggou(i,ll,rr);
else
{
chonggou(i,-1,-1);
long long aa=LLONG_MAX;
for(int k=ll;k<=rr;k++)aa=min(aa,dist[a[k]]);
ans[j]=min(ans[j],aa);
}
}
}
}
for(int i=1;i<=m;i++)if(OP[i]==2)printf("%lld\n",ans[i]);
return 0;
}