想出正解之后感觉不太会缩点,今天学了一下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]]);
}