SP4155

题解里貌似没有树链剖分的写法?那蒟蒻来一发。

题目给定 \(n\) 个开始时不连通的点,每个点有点权,要求满足三个操作。

  • 判断两个输入的节点之间是否连通,如果不连通则在两点之间连边。
  • 单点修改。
  • 输出两个输入的节点之间路径长度。

因为题目没有强制在线,所以可以尝试使用离线建树,然后树剖套线段树维护。

因为要先离线把整棵树给建出来,所以先处理所有连边的操作,而维护连通性,很容易想得到并查集。

预处理之后树剖,注意这题不保证最后连通,所以对于森林中的每棵树都要跑一遍树剖。

之后就是转在线处理问题,并查集判联通,单修和查询都是裸的树剖操作。

毕竟题目没有要求 Cut 操作,所以不必用 LCT(其实是蒟蒻不会)。

时间复杂度是 \(O(nlog_2^2n)\),比 LCT 多了一个 log。

放一下蒟蒻丑陋的代码:

#include <bits/stdc++.h>
#define V e[i].v
#define g() getchar()
#define int long long
#define lc p<<1
#define rc p<<1|1
using namespace std;char RD(){char q=g();while (q<'a'||q>'z')q=g();return q;}
int rd(){int x=0,f=0;char ch=g();while(ch<'0'||ch>'9')f|=ch=='-',ch=g();while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=g();return f?-x:x;}
const int N=1e6,INF=2e9;char O;int n,m,fir[N],cnt,tp,tot,fa[N],si[N],d[N],h[N],t[N],id[N],di[N],a[N],b[N],vis[N],f[N];
struct edge{int v,nt;}e[N<<1];void into(int u,int v){e[++cnt].v=v;e[cnt].nt=fir[u];fir[u]=cnt;}
void dfs1(int u,int f){
	fa[u]=f;si[u]=1;for(int i=fir[u];i;i=e[i].nt)if(V!=fa[u]) 
	{d[V]=d[u]+1;dfs1(V,u);if(si[V]>si[h[u]])h[u]=V;si[u]+=si[V];}
}void dfs2(int u,int anc){
	t[u]=anc;id[u]=++tot;a[tot]=b[u];if(!h[u])return ;dfs2(h[u],anc);
	for(int i=fir[u];i;i=e[i].nt)if(V!=fa[u]&&V!=h[u])dfs2(V,V);
}struct tree{int l,r,z;}s[N<<2];void pushup(int p){s[p].z=s[lc].z+s[rc].z;}
void build(int p,int l,int r){s[p].l=l;s[p].r=r;if(l==r){s[p].z=a[l];return ;}int mid=(l+r)>>1;build(lc,l,mid);build(rc,mid+1,r);pushup(p);}
void update(int p,int x,int k){if(s[p].l==s[p].r){s[p].z=k;return ;}int mid=(s[p].l+s[p].r)>>1;if(x<=mid)	update(lc,x,k);else update(rc,x,k);pushup(p);}
int Q(int p,int l,int r){if(s[p].l>=l&&s[p].r<=r)return s[p].z;int mid=(s[p].l+s[p].r)>>1,val=0;if(l<=mid)val+=Q(lc,l,r);if(r>mid)val+=Q(rc,l,r);return val;}
int ask(int u,int v){
	int ans=0;while(t[u]!=t[v]){if(d[t[u]]<d[t[v]])swap(u,v);ans+=Q(1,id[t[u]],id[u]);u=fa[t[u]];}
	if(d[u]>d[v])swap(u,v);return ans+Q(1,id[u],id[v]);
}struct in{char op;int x,y;}r[N];int C(int x){return x==f[x]?x:f[x]=C(f[x]);}
signed main(){
	n=rd();for(int i=1;i<=n;i++){b[i]=rd();f[i]=i;}m=rd();
	for(int i=1,u,v;i<=m;i++){O=RD();u=rd();v=rd();if(O=='b'&&C(u)!=C(v))into(u,v),into(v,u),f[C(v)]=C(u);r[++tp].op=O;r[tp].x=u;r[tp].y=v;}
	for(int i=1,j=C(i);i<=n;i++,j=C(i))if(vis[j])continue;else	vis[j]++,dfs1(i,0),dfs2(i,i);
	build(1,1,n);for(int i=1;i<=n;i++)	f[i]=i;
	for(int i=1;i<=tp;i++){
		if(r[i].op=='b')if(C(r[i].x)!=C(r[i].y))f[C(r[i].y)]=C(r[i].x),puts("yes");else	puts("no");
		else if(r[i].op=='e')if(C(r[i].x)!=C(r[i].y))puts("impossible");else cout<<ask(r[i].x,r[i].y)<<endl;
		else update(1,id[r[i].x],r[i].y);
	}return 0;
}
上一篇:数据结构-栈的链式存储


下一篇:Codeforces Round #560 (Div. 3)