894E - Ralph and Mushrooms 缩点/dp

想出正解之后感觉不太会缩点,今天学了一下tarjan,发现就是遍历边。。tarjan只是过程,存反向边dfs两次分解scc也能做

#include<bits/stdc++.h>  
//#pragma comment(linker, "/STACK:1024000000,1024000000")   
#include<stdio.h>  
#include<algorithm>  
#include<queue>  
#include<string.h>  
#include<iostream>  
#include<math.h>  
#include<set>  
#include<map>  
#include<vector>  
#include<iomanip>  
using namespace std;  
#define ll long long  
#define pb push_back  
#define FOR(a) for(int i=1;i<=a;i++) 
#define sqr(a) (a)*(a)

const int maxn=1e6+7;

int n,m,st;
ll psum[maxn];

ll calc(ll x){
	ll i=sqrt(2*x);
	while(i*(i+1)<2*x)i++;
	return i*x-(i*(i+1)*(i-1)/6);
}

ll dp[maxn];

struct EDGE{
	int from,to,d,nxt;
	bool sign;	//桥
}edge[maxn<<1];
int head[maxn],edgenum;
void add(int u,int v,int d){
	edge[edgenum]=(EDGE){u,v,d,head[u]};head[u]=edgenum++;
}
int DFN[maxn],Low[maxn],Stack[maxn],top,Time;
//Low[u]是u的子树反向弧能指向的最靠近总根的祖先的时间戳
int taj;
int Belong[maxn];	//连通分量所属
bool Instack[maxn];
vector<int>bcc[maxn];

void tarjan(int u,int fa){
	DFN[u]=Low[u]=++Time;
	Stack[top++]=u;
	Instack[u]=1;
	for(int i=head[u];~i;i=edge[i].nxt){
		int v=edge[i].to;
		if(DFN[v]==-1){
			tarjan(v,u);
			Low[u]=min(Low[u],Low[v]);
			if(DFN[u]<Low[v]){		//v上不去
				edge[i].sign=1;
			}
		}else if(Instack[v])Low[u]=min(Low[u],DFN[v]);
	}
	if(Low[u]==DFN[u]){
		int now;
		taj++;bcc[taj].clear();
		do{
			now=Stack[--top];
			Instack[now]=0;
			Belong[now]=taj;
			bcc[taj].pb(now);
		}while(now!=u);
	}
}
void tarjan_init(int all){
	memset(DFN,-1,sizeof DFN);
	memset(Instack,0,sizeof Instack);
	top=Time=taj=0;
	for(int i=1;i<=all;i++)if(DFN[i]==-1)tarjan(i,i);
}
struct NODE{
	int v;
	int d;
};
vector<NODE>G[maxn];
int du[maxn];
void suodian(){
	memset(du,0,sizeof du);
	for(int i=1;i<=taj;i++)G[i].clear();
	for(int i=0;i<edgenum;i++){
		int u=Belong[edge[i].from],v=Belong[edge[i].to];
		if(u!=v){
			G[u].pb((NODE){v,edge[i].d});du[v]++;
		}
		else{psum[u]+=calc(edge[i].d);}
	}
}
void init(){memset(head,-1,sizeof head);}

int vis[maxn];
void dfs(int u){
	vis[u]=1;dp[u]=0;
	for(int i=0;i<G[u].size();i++){
		if(!vis[G[u][i].v])dfs(G[u][i].v);
		dp[u]=max(dp[u],dp[G[u][i].v]+G[u][i].d);
	}
	dp[u]+=psum[u];
}

int main(){
	scanf("%d%d",&n,&m);
	init();
	FOR(m){
		int u,v,w;scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
	}
	scanf("%d",&st);
	tarjan_init(n);
	suodian();
	dp[Belong[st]]=psum[Belong[st]];
	dfs(Belong[st]);
	printf("%lld\n",dp[Belong[st]]);
}


阅读更多
个人分类: Tarjan
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭