Loading

[CF1801E] Gasoline prices 做题记录

套路题。link

并查集,至多合并 \(n - 1\) 次。可以启发式合并,问题转化为找到路径上第一个颜色不同的点。

二分 + 哈希,树状数组查询一段路径的哈希值即可。

点击查看代码
#include <bits/stdc++.h>
#define il inline
using namespace std;
typedef long long ll;
const ll mod=1e9+7,mul=19260817;
il ll qp(ll a,ll b){
    ll ans=1ll;
    while(b){
        if(b&1) ans=(ans*a)%mod;
        a=(a*a)%mod,b>>=1;
    }
    return ans;
}
il ll inv(ll a){return qp(a,mod-2ll);}
il int read(){
    int x=0,c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=x*10+c-48,c=getchar();
    return x;
}
il void ad(ll &x,ll y){x=(x+y>=mod?x+y-mod:x+y);}
il void dl(ll &x,ll y){x=(x<y?x-y+mod:x-y);}
il ll ad1(ll x,ll y){return (x+y>=mod?x+y-mod:x+y);}
il ll dl1(ll x,ll y){return (x<y?x-y+mod:x-y);}
const int N=2e5+5;
int n,m,fa[N][20],de[N],dfn[N],cnt,id[N],s[N],lg[N],f[N],siz[N];ll l[N],r[N],ans;
ll h[N],pw[N],iv[N];
struct BIT{
    ll t[N],val[N];
    il BIT(){memset(t,0,sizeof(t));memset(val,0,sizeof(val));}
    il void add(int x,ll v){while(x<=n) ad(t[x],v),x+=(x&-x);}
    il ll get(int x){ll ret=0ull;while(x) ad(ret,t[x]),x-=(x&-x);return ret;}
    il void update(int x,ll v){add(dfn[x],dl1(v,val[x])),add(dfn[x]+s[x],dl1(val[x],v)),val[x]=v;}
    il ll calc(int x){return get(dfn[x]);}
}A,B;
vector<int> e[N],g[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
il void Union(int x,int y){
    x=find(x),y=find(y);if(x==y) return ;
    if(siz[x]<siz[y]) swap(x,y);
    f[y]=x,siz[x]+=siz[y];
    ans=(ans*inv(r[x]-l[x]+1ll)%mod*inv(r[y]-l[y]+1ll))%mod;
    l[x]=max(l[x],l[y]),r[x]=min(r[x],r[y]);if(l[x]>r[x]) ans=0ll;else ans=(ans*(r[x]-l[x]+1ll))%mod;
    for(int u:g[y]) g[x].push_back(u),A.update(u,(1ll*x*pw[de[u]])%mod),B.update(u,(1ll*x*iv[de[u]])%mod);
}
void dfs(int x){
    de[x]=de[fa[x][0]]+1,dfn[x]=++cnt,id[cnt]=x,s[x]=1;
    for(int i=1;i<=18;++i) fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int y:e[x]) dfs(y),s[x]+=s[y];
}
il int lca(int x,int y){
    if(de[x]<de[y]) swap(x,y);
    while(de[x]>de[y]) x=fa[x][lg[de[x]-de[y]]];
    if(x==y) return x;
    for(int i=18;i>=0;--i) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
il int jump(int x,int k){//k-th ancestor of x
    for(int i=18;i>=0;--i) if(k>=(1<<i)) k-=(1<<i),x=fa[x][i];
    return x;
}
il int getk(int x,int y,int z,int k){//k-th point on path x-y
    int u=de[x]+de[y]-2*de[z]+1;
    if(z==x) return jump(y,u-k);
    if(k<=de[x]-de[z]+1) return jump(x,k-1);
    return jump(y,u-k);
}
il ll get(int x,int y,int z){
    if(x==z) return ((A.calc(y)-A.calc(fa[x][0])+mod)*iv[de[x]])%mod;
    int w=de[x]-2*de[z];ll u=((B.calc(x)-B.calc(z)+mod)*pw[de[x]])%mod,v=((A.calc(y)-A.calc(fa[z][0])+mod)*(w>=0?pw[w]:iv[-w]))%mod;
    return ad1(u,v);
}
il int ck(int a,int b,int x,int c,int d,int y,int k){
    int u=getk(a,b,x,k),v=getk(c,d,y,k),p=0,q=0;
    if(k<=de[a]-de[x]+1) p=u;else p=x;
    if(k<=de[c]-de[y]+1) q=v;else q=y;
    return get(a,u,p)==get(c,v,q);
}
il void init(){
    pw[0]=iv[0]=1ull;ll x=qp(mul,mod-2ll);
    for(int i=1;i<=n;++i) pw[i]=(pw[i-1]*mul)%mod,iv[i]=(iv[i-1]*x)%mod;
    for(int i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
}
int a,b,c,d,len,x,y,z,u,v,w,L,R,mid,ret;
int main(){
    scanf("%d",&n);ans=1ll,init();
    for(int i=2;i<=n;++i) fa[i][0]=read(),e[fa[i][0]].push_back(i);
    for(int i=1;i<=n;++i) l[i]=read(),r[i]=read(),f[i]=i,siz[i]=1,g[i].push_back(i),ans=(ans*(r[i]-l[i]+1ll))%mod;
    dfs(1);
    for(int i=1;i<=n;++i) A.update(i,(1ll*i*pw[de[i]])%mod),B.update(i,(1ll*i*iv[de[i]])%mod);
    scanf("%d",&m);
    while(m--){
        a=read(),b=read(),c=read(),d=read();
        if(!ans){puts("0");continue;}
        x=lca(a,b),y=lca(c,d),len=de[a]+de[b]-2*de[x]+1;
        while(get(a,b,x)!=get(c,d,y)){
            L=1,R=len,ret=0;
            while(L<=R){
                mid=(L+R)>>1;
                if(!ck(a,b,x,c,d,y,mid)) ret=mid,R=mid-1;
                else L=mid+1;
            }
            u=getk(a,b,x,ret),v=getk(c,d,y,ret);
            Union(u,v);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2025-02-01 11:57  Lgx_Q  阅读(11)  评论(0)    收藏  举报