http://lx.lanqiao.cn/problem.page?gpid=T22
因为有负权边 只能用spfa 但是数据比较强 只能做到95分。。 可能有其他方法吧
主要记一下spfa两种优化
第一种是SLF 就是改用双端队列 当一个点v入队列时 判断其和队首点front的大小关系 如果队列为空或者dis[v]>=dis[front] 则把v扔到队尾 否则扔到队首
第二种是LLL 在循环开始处弹出队首点时 如果当前队首点的平均值大于队列中所有点的平均值 则将其扔至队尾 直至当前队首的点小于等于平均值 才真正将其弹出队列
using namespace std;
typedef long long ll;
const int N=0x3f3f3f3f;
const int maxn=3e4+10;
const int maxm=5e4+10;
struct node
{
int v,w,next;
};
deque <int> que;
node edge[3*maxm];
int first[maxn],dis[maxn],book[maxn];
int n,m1,m2,s,num;
template <class T>
inline void _cin(T &ret) //读正负整数 (int, long long)
{
char ch;
int flag = 0;
while((ch = getchar()) < '0' || ch > '9')
{
if(ch == '-') flag = 1;
}
for(ret = 0; ch >= '0' && ch <= '9'; ch = getchar())
ret = ret * 10 + ch - '0';
if(flag) ret *= -1;
}
void addedge(int u,int v,int w)
{
edge[num].v=v;
edge[num].w=w;
edge[num].next=first[u];
first[u]=num++;
}
void spfa()
{
ll sum;
int i,u,v,w,cnt;
memset(dis,0x3f,sizeof(dis));
dis[s]=0,book[s]=1;
que.push_back(s);
cnt=1,sum=0;
while(!que.empty()){
u=que.front();
while(ll(cnt)*ll(dis[u])>sum){
//printf("*%d*\n",u);
que.pop_front();
que.push_back(u);
u=que.front();
}
que.pop_front();
book[u]=0;
cnt--,sum-=dis[u];
for(i=first[u];i!=-1;i=edge[i].next){
v=edge[i].v,w=edge[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!book[v]){
book[v]=1;
if(que.empty()||dis[v]>dis[que.front()]) que.push_back(v);
else que.push_front(v);
cnt++,sum+=dis[v];
}
}
}
}
}
int main()
{
int i,u,v,w;
//scanf("%d%d%d%d",&n,&m1,&m2,&s);
_cin(n),_cin(m1),_cin(m2),_cin(s);
memset(first,-1,sizeof(first));
num=0;
for(i=1;i<=m1;i++){
//scanf("%d%d%d",&u,&v,&w);
_cin(u),_cin(v),_cin(w);
addedge(u,v,w);
addedge(v,u,w);
}
for(i=1;i<=m2;i++){
//scanf("%d%d%d",&u,&v,&w);
_cin(u),_cin(v),_cin(w);
addedge(u,v,w);
}
spfa();
for(i=1;i<=n;i++){
if(dis[i]==N) printf("NO PATH\n");
else printf("%d\n",dis[i]);
}
return 0;
}