2019.01.19【BZOJ3281】小P的烦恼(支配树)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/86550293

传送门


解析:

首先本题数据不是DAG。。。对的就是数据有误

不然有更加优秀的做法。。。

思路:

必经边是吧,那就化边为点建立支配树。

跑最短路,因为我们要覆盖。。

然后我们把所有必经边取出来DP出前缀和后缀单条最大值,

然后考虑两条在某一个端点重合,再来一次DP。

然后统计一下答案和剩余的必经边的权值。
完了。

如果是DAG的话判断必经边可以做到 O ( n + m ) O(n+m) 而不是 L e n g a u e r T a r j a n Lengauer-Tarjan O ( ( n + m ) log n ) O((n+m)\log n) 。我们只需要正反拓扑序DP记录一下 S S T T 到每个点的方案数。枚举每条边,如果 c n t S u × c n t T v = = c n t S T cntS_u\times cntT_v==cntS_T 那么这条边就是必经边了。

DAG的代码我放最下面了,自己造DAG对拍了一个多小时,应该没有问题。

如果你对拍出问题,请告知博主,谢谢!


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define cs const

namespace IO{
	namespace IOONLY{
		cs int Rlen=1<<20|1;
		char buf[Rlen],*p1,*p2;
	}
	inline char get_char(){
		using namespace IOONLY;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++; 
	}
	
	inline int getint(){
		re int num;
		re char c;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
}
using namespace IO;

cs int N=300005;

int n,m,S,T,L;

vector<int> g[N],revg[N];

int val[N];

int dist[N];

inline void Dij(){
	memset(dist,0x3f,sizeof(int)*(m+n+1));
	set<pair<int,int> > q;
	q.insert(make_pair(dist[S]=0,S));
	while(!q.empty()){
		int u=q.begin()->second;
		q.erase(q.begin());
		for(int re e=0,v;e<g[u].size();++e){
			v=g[u][e];
			if(dist[v]>dist[u]+val[v]){
				q.erase(make_pair(dist[v],v));
				dist[v]=dist[u]+val[v];
				q.insert(make_pair(dist[v],v));
			}
		}
	}
}
int dfn[N],id[N],fa[N],dfs_clock;
void dfs(int u){
	id[dfn[u]=++dfs_clock]=u;
	for(int re e=0,v;e<g[u].size();++e){
		v=g[u][e];
		if(dfn[v])continue;
		fa[v]=u;dfs(v);
	}
} 

stack<int,vector<int> > dom[N];

int bel[N],nd[N],semi[N],idom[N];
inline int getfa(int x){
	if(x==bel[x])return x;
	int tmp=getfa(bel[x]);
	if(dfn[semi[nd[bel[x]]]]<dfn[semi[nd[x]]])nd[x]=nd[bel[x]];
	return bel[x]=tmp;
}

inline void tarjan(){
	for(int re i=dfs_clock,u;i>1;--i){
		u=id[i];
		for(int re e=0,v;e<revg[u].size();++e){
			v=revg[u][e];
			if(!dfn[v])continue;
			getfa(v);
			if(dfn[semi[nd[v]]]<dfn[semi[u]])semi[u]=semi[nd[v]];
		}
		dom[semi[u]].push(u);
		u=bel[u]=fa[u];
		while(!dom[u].empty()){
			int v=dom[u].top();dom[u].pop();
			getfa(v);
			if(semi[nd[v]]==u)idom[v]=u;
			else idom[v]=nd[v];
		}
	}
	for(int re i=2,u;i<=dfs_clock;++i){
		u=id[i];
		if(semi[u]^idom[u])idom[u]=idom[idom[u]];
	}
}

int q[N],qn;
int pre[N],suf[N];

inline void solve(){
	n=getint();m=getint();
	S=getint()+1;T=getint()+1;
	L=getint();
	for(int re i=1;i<=m;++i){
		int u=getint()+1,v=getint()+1;
		g[u].push_back(i+n);revg[i+n].push_back(u);
		g[i+n].push_back(v);revg[v].push_back(i+n);
		val[i+n]=getint();
	}
	dfs(S);if(dfn[T]==0){puts("-1");return ;}
	for(int re i=1;i<=n+m;++i)nd[i]=semi[i]=bel[i]=i;
	tarjan();
	Dij();
	qn=0;
	for(int re u=T;u^S;u=idom[u])if(u>n)q[++qn]=u;
	q[qn+1]=0;
	for(int re l=1,r=1,tmp=0;r<=qn;++r){
		tmp+=l==r?0:val[q[r]];
		while(dist[q[l]]-dist[q[r]]+val[q[r]]-val[q[l]]>L)tmp-=val[q[++l]];
		int len=tmp+min(L-(dist[q[l]]-dist[q[r]]+val[q[r]]-val[q[l]]),val[q[l]]);
		pre[r]=max(pre[r-1],len);
	}
	suf[qn+1]=0;
	for(int re l=qn,r=qn,tmp=0;l;--l){
		tmp+=l==r?0:val[q[l]];
		while(dist[q[l]]-dist[q[r]]>L)tmp-=val[q[--r]];
		int len=tmp+min(L-(dist[q[l]]-dist[q[r]]),val[q[r]]);
		suf[l]=max(suf[l+1],len);
	}
	
	int ans=0;
	for(int re i=1;i<=qn+1;++i)ans=max(ans,pre[i-1]+suf[i]);
	L<<=1;
	for(int re l=qn,r=qn,tmp=0;l;--l){
		tmp+=l==r?0:val[q[l]];
		while(dist[q[l]]-dist[q[r]]>L)tmp-=val[q[--r]];
		int len=tmp+min(L-(dist[q[l]]-dist[q[r]]),val[q[r]]);
		suf[l]=max(suf[l+1],len);
	}
	ans=-max(ans,suf[1]);
	for(int re i=1;i<=qn;++i)ans+=val[q[i]];
	printf("%d\n",ans);
}

inline void init(){
	for(int re i=1;i<=n+m;++i){
		val[i]=dfn[i]=0;
		g[i].clear();
		revg[i].clear();
	}
	dfs_clock=0;
}

signed main(){
	for(int re T=getint();T--;)init(),solve();
	return 0;
} 

代码( D A G DAG ):

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc putchar
#define cs const

namespace IO{
	namespace IOONLY{
		cs int Rlen=1<<20|1;
		char buf[Rlen],*p1,*p2;
	}
	inline char get_char(){
		using namespace IOONLY;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re int num;
		re char c;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
}
using namespace IO;

cs int N=100005;
vector<int> g[N],rg[N];
vector<int> w[N];
int deg[N],rdeg[N];

int n,m,S,T,L;

cs ll mod=9999999999999937;
inline ll add(ll a,ll b){return a+b>=mod?a+b-mod:a+b;}
inline ll mul(ll a,ll b){return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;}
ll cntS[N],cntT[N];
int dfnS[N],dfnT[N];
int idS[N],idT[N];
inline void topsort(int S,vector<int> *edge,ll *cnt,int *du,int *dfn,int *id){
	cnt[S]=1;
	queue<int> q;
	re int topsort_clock=0;
	for(int re i=1;i<=n;++i)if(!du[i])q.push(i);
	while(!q.empty()){
		re int u=q.front();q.pop();
		id[dfn[u]=++topsort_clock]=u;
		for(int re e=0,v;e<edge[u].size();++e){
			v=edge[u][e];
			cnt[v]=add(cnt[v],cnt[u]);
			if(!(--du[v]))q.push(v);
		}
	}
//	assert(topsort_clock==n);
}

int dist[N];

inline void Dij(){
	memset(dist+1,0x3f,sizeof(int)*n);
	set<pair<int,int> > q;
	q.insert(make_pair(dist[S]=0,S));
	while(!q.empty()){
		re int u=q.begin()->second;
		q.erase(q.begin());
		for(int re e=0,v;e<g[u].size();++e){
			v=g[u][e];
			if(dist[v]>dist[u]+w[u][e]){
				q.erase(make_pair(dist[v],v));
				dist[v]=dist[u]+w[u][e];
				q.insert(make_pair(dist[v],v));
			}
		}
	}
}

int dis[N],val[N],qn;
int pre[N],suf[N];
inline void solve(){
	n=getint();m=getint();
	S=getint()+1;T=getint()+1;
	L=getint();
	for(int re i=1;i<=m;++i){
		int u=getint()+1,v=getint()+1,val=getint();
		g[u].push_back(v);++deg[v];
		rg[v].push_back(u);++rdeg[u];
		w[u].push_back(val);
	}
	topsort(S,g,cntS,deg,dfnS,idS);if(cntS[T]==0){puts("-1");return ;}
	topsort(T,rg,cntT,rdeg,dfnT,idT);
	Dij();qn=0;
	for(int re i=dfnT[T]+1;i<=dfnT[S];++i){
		int u=idT[i];
		if(dfnS[S]<=dfnS[u]&&dfnS[u]<=dfnS[T]&&cntS[u]&&cntT[u]){
			for(int re e=0,v;e<g[u].size();++e){
				v=g[u][e];
				if(mul(cntS[u],cntT[v])==cntS[T]){
					dis[++qn]=dist[u];
					val[qn]=w[u][e];
					break;
				}
			}
		}
	}
	dis[qn+1]=0;val[qn+1]=0;
	for(int re l=1,r=1,tmp=0;r<qn;++r){
		tmp+=l==r?0:val[r];
		while(dis[l]-dis[r]+val[r]-val[l]>L)tmp-=val[++l];
		int len=tmp+min(L-(dis[l]-dis[r]+val[r]-val[l]),val[l]);
		pre[r]=max(pre[r-1],len);
	}
	suf[qn+1]=0;
	for(int re l=qn,r=qn,tmp=0;l;--l){
		tmp+=l==r?0:val[l];
		while(dis[l]-dis[r]>L)tmp-=val[--r];
		int len=tmp+min(L-(dis[l]-dis[r]),val[r]);
		suf[l]=max(suf[l+1],len);
	}
	int ans=0;
	for(int re i=1;i<=qn+1;++i)ans=max(ans,pre[i-1]+suf[i]);
	L<<=1;
	for(int re l=qn,r=qn,tmp=0;l;--l){
		tmp+=l==r?0:val[l];
		while(dis[r]-dis[l]>L)tmp-=val[--r];
		int len=tmp+min(L-(dis[l]-dis[r]),val[r]);
		suf[l]=max(suf[l+1],len);
	}
	ans=-max(ans,suf[1]);
	for(int re i=1;i<=qn;++i)ans+=val[i];
	printf("%d\n",ans);
}

inline void init(){
	for(int re i=1;i<=n;++i){
		g[i].clear();rg[i].clear();
		w[i].clear();
		cntS[i]=cntT[i]=0;
		dfnS[i]=dfnT[i]=0;
	}
}

signed main(){
	for(int re T=getint();T--;)init(),solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/86550293
今日推荐