• P7737-[NOI2021]庆典【tarjan,虚树】


    正题

    题目链接:https://www.luogu.com.cn/problem/P7737


    题目大意

    给出一张无向图满足若(xRightarrow z,yRightarrow z)那么有(xRightarrow y)(yRightarrow x)

    (q)次询问给出起点和终点和(k)条临时的边,求可能经过点的数量

    (1leq n,qleq 3 imes 10^5,0leq kleq 2)


    解题思路

    那个条件就是说我们缩点之后可以找出一个联通性和原图相同的树。

    先缩点然后和原图相同的树的话我们用拓扑排序找,让每个点入栈的那个点就是它的父节点。

    然后因为最多加两条边所以我们可以把有影响的点找出来构成一棵虚树然后暴力跑出答案就好了。

    时间复杂度(O(n+Qk))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<cctype>
    #include<iostream>
    using namespace std;
    const int N=3e5+10,Z=18;
    struct node{
    	int to,next,w;
    }a[N];
    int n,m,Q,k,dcc,cnt,dfr,top,tot,clt,ans,num,p[7];
    int dfn[N],low[N],v[N],ls[N],rt[N],cl[N],dep[N];
    int f[N][Z+1],col[N],siz[N],in[N],st[N],dis[N],ed[N];
    bool ins[N];stack<int>S;queue<int>q;
    vector<int>G[N],F[N],T[N],D[N]; 
    inline char Getchar()
    {
        static char buf[100000],*p1=buf+100000,*pend=buf+100000;
        if(p1==pend)
    	{
            p1=buf; pend=buf+fread(buf,1,100000,stdin);
            if (pend==p1) return -1;
        }
        return *p1++;
    }
    inline int read()
    {
    	char c;int d=1;int f=0;
    	while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
    	while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
    	return d*f;
    }
    inline void tarjan(int x){
    	dfn[x]=low[x]=++cnt;
    	ins[x]=1;S.push(x);
    	for(int i=0;i<G[x].size();i++){
    		int y=G[x][i];
    		if(!dfn[y]){
    			tarjan(y);
    			low[x]=min(low[x],low[y]);
    		}
    		else if(ins[y])
    			low[x]=min(low[x],dfn[y]);
    	}
    	if(low[x]==dfn[x]){
    		++dcc;
    		while(S.top()!=x){
    			col[S.top()]=dcc;
    			ins[S.top()]=0;
    			siz[dcc]++;S.pop();
    		}
    		col[x]=dcc;ins[x]=0;
    		siz[dcc]++;S.pop();
    	}
    	return;
    }
    inline void Topsort(){
    	for(int i=1;i<=dcc;i++)
    		if(!in[i])rt[i]=i,q.push(i);
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		for(int i=0;i<F[x].size();i++){
    			int y=F[x][i];in[y]--;
    			if(!in[y]){
    				q.push(y);
    				T[x].push_back(y);
    			}
    		}
    	}
    	return;
    }
    inline void dfs(int x,int fa){
    	dis[x]=dis[fa]+siz[x];
    	dep[x]=dep[fa]+1;dfn[x]=++dfr;
    	for(int i=0;i<T[x].size();i++){
    		int y=T[x][i];
    		if(y==fa)continue;
    		f[y][0]=x;rt[y]=rt[x];
    		dfs(y,x);
    	}
    	ed[x]=dfr;return;
    }
    inline int LCA(int x,int y){
    	if(dep[x]>dep[y])swap(x,y);
    	for(int i=Z;i>=0;i--)
    		if(dep[f[y][i]]>=dep[x])y=f[y][i];
    	if(x==y)return x;
    	for(int i=Z;i>=0;i--)
    		if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    inline bool cmp(int x,int y)
    {return dfn[x]<dfn[y];}
    inline void addl(int x,int y,int w){
    	a[++tot].to=y;
    	a[tot].next=ls[x];
    	a[tot].w=(dis[y]-dis[x]-siz[y])*w;
    	D[y].push_back(x);ls[x]=tot;return;
    }
    inline void Add(int x){
    	if(rt[st[top]]!=rt[x]){
    		while(top>1)addl(st[top-1],st[top],1),top--;
    		if(x!=rt[x])st[top]=rt[x],cl[++clt]=x;
    	}
    	if(!top){st[++top]=x;cl[++clt]=x;return;}
    	int lca=LCA(st[top],x);
    	while(top>1&&dep[st[top-1]]>dep[lca])
    		addl(st[top-1],st[top],1),top--;
    	if(dep[st[top]]>dep[lca])addl(lca,st[top],1),top--;
    	if((!top)||(st[top]!=lca))st[++top]=lca,cl[++clt]=lca;
    	st[++top]=x;cl[++clt]=x;
    }
    inline void mark(int x){
    	v[x]=1;
    	for(int i=0;i<D[x].size();i++)
    		if(!v[D[x][i]])
    		mark(D[x][i]);
    	return;
    }
    inline void calc(int x){
    	if(v[x])ans+=siz[x];v[x]|=2;
    	for(int i=ls[x];i;i=a[i].next){
    		int y=a[i].to;
    		if(v[y]&1)ans+=a[i].w,a[i].w=0;
    		if((v[y]&2)||!(v[y]&1))continue; 
    		calc(y);
    	}
    	return;
    }
    signed main()
    {
    	freopen("P7737_12.in","r",stdin);
    	freopen("data.out","w",stdout);
    	n=read();m=read();Q=read();k=read();
    	for(int i=1;i<=m;i++){
    		int x=read(),y=read();
    		G[x].push_back(y);
    	}
    	for(int i=1;i<=n;i++)
    		if(!dfn[i])tarjan(i);
    	for(int x=1;x<=n;x++)
    		for(int i=0;i<G[x].size();i++){
    			int y=G[x][i];
    			if(col[x]==col[y])continue;
    			F[col[x]].push_back(col[y]);in[col[y]]++;
    		}
    	Topsort();n=dcc;
    	for(int i=1;i<=n;i++)
    		if(rt[i]==i)dfs(rt[i],0);
    	for(int j=1;j<=Z;j++)
    		for(int i=1;i<=n;i++)
    			f[i][j]=f[f[i][j-1]][j-1];
    	while(Q--){
    		int s=read(),t=read();
    		s=col[s];t=col[t];
    		p[1]=s;p[2]=t;num=2;
    		tot=clt=top=ans=0;
    		for(int i=1;i<=k;i++){
    			int x=read(),y=read();
    			x=col[x];y=col[y];
    			p[++num]=x;p[++num]=y;
    			addl(x,y,0);
    		}
    		sort(p+1,p+1+num,cmp);
    		num=unique(p+1,p+1+num)-p-1;
    		for(int i=1;i<=num;i++)Add(p[i]);
    		while(top>1)addl(st[top-1],st[top],1),top--;
    		mark(t);calc(s);
    		cout<<ans<<'
    ';
    		for(int i=1;i<=clt;i++){
    			ls[cl[i]]=v[cl[i]]=0;
    			if(D[cl[i]].size())D[cl[i]].clear();
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    [zt]Delphi API HOOK完全说明(存在错误的原文,含修正)
    【zt】delphi线程类
    Oracle:《ITPUB名人堂》第3期-对话嘉宾:张乐奕先生
    Oracle10g 预定义主要角色
    Oracle如何根据物化视图日志快速刷新物化视图
    Oracle:《ITPUB名人堂》第1期采访谭怀远先生圆满结束
    Asktom: Lock
    Oracle:Commit Enhancements in Oracle 10g Database Release 2
    Oracle在线归档重做日志概念分析
    DBMS_LOB.LOADFROMFILE
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15126005.html
Copyright © 2020-2023  润新知