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]]); }