CF1801E 题解
思路
并查集将权值相同的连在一起,取可行区间的并集。可以 \(O(n^2)\)。考虑优化,总共只有 \(n-1\) 次有效合并,只要没有重复检查已经连通的点就可以保证复杂度。
倍增 \(u\) 向上 \(2^i\) 个祖先的状态,代表从下往上和从上往下的区间。将两条路径倍增合并,\(O(\log n)\) 次合并等长区间。每次合并时向下一层递归合并,如果已经是一个连通块的及时退出。一直到单点合并时,去掉旧贡献加上新贡献。复杂度 \(O(n\log n)\)。
卡常方面,将倍增的 \(\log n\) 一维放在 \(n\) 一维前面,路径压缩加按秩合并,不开 long long
。实在过不了再交几次。
code
int n,q,ans=1;
int head[maxn],tot;
struct nd{
int nxt,to;
}e[maxn<<1];
void add(int u,int v){e[++tot]={head[u],v};head[u]=tot;}
int l[maxn],r[maxn];
inline int ksm(int a,int b=mod-2){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
int fa[18][maxn],dep[maxn];
int f[18][maxn<<1],siz[18][maxn<<1];
int fd(int x,int k){
if(x==f[k][x])return x;
return f[k][x]=fd(f[k][x],k);
}
void merge(int x,int y,int id){
// if(!id)cout<<x<<" "<<y<<"\n";
x=fd(x,id),y=fd(y,id);
if(x==y)return ;
if(siz[id][x]<siz[id][y])swap(x,y);
if(!id){
ans=1ll*ans*ksm(max(0,r[x]-l[x]+1))%mod;
ans=1ll*ans*ksm(max(0,r[y]-l[y]+1))%mod;
l[x]=max(l[x],l[y]),r[x]=min(r[x],r[y]);
ans=1ll*ans*max(0,r[x]-l[x]+1)%mod;
// cout<<x<<" "<<y<<" "<<ans<<"\n";
}
f[id][y]=x,siz[id][x]+=siz[id][y];
}
void dfs(int u){
dep[u]=dep[fa[0][u]]+1;
for(int i=1;i<=17;i++)fa[i][u]=fa[i-1][fa[i-1][u]];
for(int i=0;i<=17;i++)f[i][u]=u,siz[i][u]=1,f[i][u+n]=u+n,siz[i][u+n]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
fa[0][v]=u;dfs(v);
}
}
int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
for(int i=17;~i;i--)if(dep[fa[i][u]]>=dep[v])u=fa[i][u];
if(u==v)return u;
for(int i=17;~i;i--)if(fa[i][u]!=fa[i][v])u=fa[i][u],v=fa[i][v];
return fa[0][u];
}
int kth(int u,int k){
for(int i=17;~i;i--)if(k&(1<<i))u=fa[i][u];
return u;
}
void mer1(int u,int v,int id){
if(fd(u,id)==fd(v,id))return ;
if(!id){
merge(u,v,id);
return ;
}
merge(u,v,id);
mer1(u,v,id-1),mer1(fa[id-1][u],fa[id-1][v],id-1);
}
void mer2(int u,int v,int id){
if(fd(u,id)==fd(v+n,id))return ;
if(!id){
merge(u,v,id);
return ;
}
merge(u+n,v,id),merge(u,v+n,id);
mer2(u,fa[id-1][v],id-1),mer2(fa[id-1][u],v,id-1);
}
void work(){
n=read();
for(int i=2;i<=n;i++){
int u=read();
add(u,i);
}
dfs(1);
for(int i=1;i<=n;i++){
l[i]=read(),r[i]=read();
ans=1ll*ans*max(0,r[i]-l[i]+1)%mod;
}
q=read();
while(q--){
int a=read(),b=read(),c=read(),d=read(),tp1=lca(a,b),tp2=lca(c,d);
int dis=min(dep[a]-dep[tp1],dep[c]-dep[tp2]);
for(int i=17;~i;i--)if(dis&(1<<i))mer1(a,c,i),a=fa[i][a],c=fa[i][c];
dis=min(dep[b]-dep[tp1],dep[d]-dep[tp2]);
for(int i=17;~i;i--)if(dis&(1<<i))mer1(b,d,i),b=fa[i][b],d=fa[i][d];
// cout<<tp1<<" "<<tp2<<" "<<ans<<"\n";
if(a==tp1){
dis=dep[b]-dep[tp1]+1;
for(int i=17;~i;i--)if(dis&(1<<i))dis^=(1<<i),mer2(b,kth(c,dis),i),b=fa[i][b];
}
else{
dis=dep[a]-dep[tp1]+1;
for(int i=17;~i;i--)if(dis&(1<<i))dis^=(1<<i),mer2(a,kth(d,dis),i),a=fa[i][a];
}
printf("%d\n",ans);
}
}