• 983E


    http://codeforces.com/problemset/problem/983/E

    题意:给定一棵树,给m个公交车路线,即从u到v可直达不用换乘,给q次查询,问从u,v最少需要多少次换乘

    题解:考虑到查询操作我们可以分成两部分u->lca(u,v)->v,对于u->lca这段路我们找到t,即从t->lca只需要一次换乘,对于右边路径,我们需要找到一个点z,使得t->z有一次换乘的路径(通过主席树来维护t的子树和z的子树之间是否有直达路线),满足单调性,所以二分查找最合适的z,然后加上前半部分的贡献即为所求

    #include <bits/stdc++.h>
    #define ll long long
    #define s second
    #define f first
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=2e5+10;
    const int K=20;
    using namespace std;
    vector<int>vec[MAXN];
    int num[MAXN],son[MAXN],fa[MAXN],dep[MAXN],f[MAXN];
    int st[MAXN][21];
    int n,m,q;
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return f*x;
    }
    void dfs1(int v,int pre,int deep){
    	num[v]=1;fa[v]=pre;dep[v]=deep+1;
    	for(int i=0;i<vec[v].size();i++){
    		int u=vec[v][i];
    		if(u!=pre){
    			dfs1(u,v,deep+1);
    			num[v]+=num[u];
    			if(son[v]==-1||num[son[v]]<num[u])son[v]=u;
    		}
    	}
    }
    int p[MAXN],fp[MAXN],cnt,tp[MAXN],rt[MAXN];
    void dfs2(int v,int td){
    	p[v]=++cnt;fp[cnt]=v;tp[v]=td;
    	if(son[v]!=-1) dfs2(son[v],td);
    	for(int i=0;i<vec[v].size();i++)if(son[v]!=vec[v][i]&&vec[v][i]!=fa[v])dfs2(vec[v][i],vec[v][i]);
    }
    int Lca(int u,int v){
    	int uu=tp[u];int vv=tp[v];
    	while(uu!=vv){
    		if(dep[uu]<dep[vv]) swap(uu,vv),swap(u,v);
    		u=fa[uu];uu=tp[u];
    	}
    	if(dep[u]>dep[v]) swap(u,v);
    	return u;
    }
    typedef struct node{
    	int l,r,sum;
    }node;
    node d[MAXN*45];int cnt1;
    int querty(int u,int v){
    	if(u==v) return 0;
    	if(dep[st[v][K]]>dep[u]) return -1;
    	int ans1=1,t=v;
    //	cout<<p[st[v][K]]<<" "<<p[u]<<endl;
    	for(int i=K;i>=0;i--){
    	if(dep[st[t][i]]>dep[u])ans1+=(1<<i),t=st[t][i];
    //	cout<<p[st[t][i]]<<" "<<p[u]<<endl;
    }
    	return ans1;
    }
    void update(int &x,int y,int l,int r,int t){
    //	cout<<l<<":::"<<r<<" "<<t<<endl;
    	x=++cnt1;d[x]=d[y];d[x].sum++;
    //	cout<<d[x].sum<<endl;
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	if(t<=mid) update(d[x].l,d[y].l,l,mid,t);
    	else update(d[x].r,d[y].r,mid+1,r,t);
    }
    int ans=0;
    void Sum(int x,int y,int l,int r,int ql,int qr){
    //	cout<<l<<" "<<r<<" "<<ans<<" "<<d[y].sum<<endl;
    	if(ql<=l&&r<=qr){ans+=(d[y].sum-d[x].sum);return ;}
    	int mid=(l+r)>>1;
    	if(ql<=mid) Sum(d[x].l,d[y].l,l,mid,ql,qr);
    	if(qr>mid) Sum(d[x].r,d[y].r,mid+1,r,ql,qr);
    }
    int erfen(int v,int mid){
    	int vv=tp[v];
    	while(1){
    		int t=p[v]-p[vv];
    		if(mid<=t) return fp[p[v]-mid];
    		mid-=(t+1);v=fa[vv];vv=tp[v];
    	}
    }
    bool check(int u,int v){if(p[v]>p[u])swap(v,u);ans=0;Sum(rt[p[v]-1],rt[p[v]+num[v]-1],1,n,p[u],p[u]+num[u]-1);return ans>0;}
    int slove(int u,int v){
    	if(u==v) return 0;
    	int lca=Lca(u,v);
    	if(lca==u||lca==v){
    		if(dep[u]>dep[v]) swap(u,v);
    		return querty(u,v);		
    	}
    	if(dep[st[u][K]]>dep[lca]) return -1;
    	int ans3=0,t=u;
    	for(int i=K;i>=0;i--)if(dep[st[t][i]]>dep[lca])ans3+=(1<<i),t=st[t][i];
    //	cout<<ans3<<endl;
    	int l=0;int r=dep[v]-dep[lca]-1;int z=dep[v]-dep[lca];
    	//cout<<l<<" "<<r<<endl;
    //	cout<<"::::"<<t<<endl;
    	while(l<=r){
    		int mid=(l+r)>>1;
    	//	cout<<t<<"---"<<erfen(v,mid)<<endl;
    //		cout<<l<<" "<<r<<" "<<erfen(v,mid)<<endl;
    		if(check(t,erfen(v,mid)))z=mid,r=mid-1;
    		else l=mid+1;
    //		cout<<l<<" "<<r<<" "<<z<<endl;
    	}
    //	cout<<erfen(v,z)<<endl;
    	int ttt=querty(erfen(v,z),v);
    //	cout<<ans3<<" "<<ttt<<endl;
    	if(ttt<0) return -1;
    	ans3+=(ttt+1);
    	return ans3;
    }
    int find1(int x){
    //	cout<<x<<"----"<<endl;
    	if(x==f[x]) return x;
    	else return f[x]=find1(f[x]);
    }
    void dfs3(int v){
    	for(int i=1;i<=K;i++) st[v][i]=st[st[v][i-1]][i-1];
    	for(int i=0;i<vec[v].size();i++)if(vec[v][i]!=fa[v])dfs3(vec[v][i]);
    }
    void merge(int u,int v){
    //	cout<<dep[u]<<" "<<dep[v]<<" "<<u<<" "<<v<<endl;
    for(u=find1(u);dep[u]>=dep[v];u=find1(u))st[u][0]=v,f[u]=fa[u];
    }
    typedef struct Node{
    	int x,y,z;
    }Node;
    Node que[MAXN];
    bool cmp1(Node aa,Node bb){
    	return dep[aa.z]<dep[bb.z];
    }
    bool cmp2(Node aa,Node bb){
    	return p[aa.x]<p[bb.x];
    }
    int main(){
    	n=read();
    	//m=read();q=read();
    	int u,v;cnt=cnt1=0;
    	for(int i=1;i<=n;i++)son[i]=-1,st[i][0]=f[i]=i;
    	//for(int i=1;i<n;i++)u=read(),v=read(),vec[u].push_back(v),vec[v].push_back(u);
    	inc(i,2,n)u=read(),vec[i].push_back(u),vec[u].push_back(i);
    	dfs1(1,0,0);dfs2(1,1);
    //	for(int i=1;i<=n;i++) cout<<p[i]<<" ";
    //	cout<<endl;
    	m=read();
    	for(int i=1;i<=m;i++){
    	u=read();v=read();
    	if(u==v) continue;
    	que[i].x=u,que[i].y=v,que[i].z=Lca(que[i].x,que[i].y);
    }
    	sort(que+1,que+m+1,cmp1);
    	for(int i=1;i<=m;i++)merge(que[i].x,que[i].z),merge(que[i].y,que[i].z);
    	for(int i=1;i<=m;i++)if(p[que[i].x]>p[que[i].y])swap(que[i].x,que[i].y);
    //	cout<<"sb"<<endl;
    //	for(int i=1;i<=n;i++) cout<<st[i][0]<<" ";
    //	cout<<endl;
    	dfs3(1);
    	sort(que+1,que+1+m,cmp2);int t=1;
    	for(int i=1;i<=cnt;i++){
    		rt[i]=rt[i-1];
    		for(;p[que[t].x]==i;t++)update(rt[i],rt[i],1,n,p[que[t].y]);
    //		ans=0;Sum(rt[3],rt[4],1,n,5,6);
    //		cout<<ans<<"==---"<<endl;
    	}
    //		ans=0;Sum(rt[3],rt[4],1,n,5,6);
    //		cout<<ans<<"==---"<<endl;
    //	cout<<"sb"<<endl;
    	q=read();
    	while(q--){
    		u=read();v=read();
    		int ans2=slove(u,v);
    		if(ans2<0) puts("-1");
    		else printf("%d
    ",ans2);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    支付宝沙箱环境应用
    七牛云视频托管
    腾讯云短息验证码接口
    git远程连接(码云)
    git
    字间距
    html文本保留空格
    mysql重启导致AUTO_INCREMENT从1开始
    js保留两位小数
    vue中watch的基本用法
  • 原文地址:https://www.cnblogs.com/wang9897/p/9049003.html
Copyright © 2020-2023  润新知