[LibreOJ 2316][NOIP2017]逛公园
给你一张n个点m条边的有向图,设从1到n的最短路为d,那么请问有多少1到n的路径(可以是非简单路径)满足其长度在[d,d+K]中,如果答案为无限大的话输出−1。
1≤n≤105,1≤m≤2×105,0≤K≤50。
[SZKOpuł ben][AMPPZ2014]Petrol
aji波兰题!(迫真)
啊波兰题真好康(一转)
考虑怎么去除非加油站的影响……对于每两个加油站,取他们的最短路,然后建出来一个图,这个图的MST上的路径的走法就事最优走法。
但这样显然会凉……因为s肥肠巨大,会T。然后我们考虑多源最短路,并且给每个点标记到它最近的加油站(称为来源)。那么考虑两条加油站间的路径,上面一定有一条边满足边两个端点不一样(证明考虑……如果所有边两边端点的来源都一样,那么所有边的来源会同时事那两个加油站)。
然后一个小问题事,如果一个点有多个来源,只考虑一个会出事吗?这个事不会的。比如说有三个加油站a、b、c,如果说三者到一个点的最短路都一样,那么我们考虑只取a。如果b和c本来能连一条边,但现在因为这个连不了了,那他们还是能同时各和a连一条长度和原来的那条边长度一样的边,所以事实上没有什么笋丝。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <utility> #include <vector> #include <queue> const int maxn = 200005, maxm = 400005; int first[maxn]; int next[maxm], to[maxm], dist[maxm]; bool dir[maxm]; void add_edge( int u, int v, int w, bool d = true ) { static int cnt = 0; cnt ++; next[cnt] = first[u]; first[u] = cnt; to[cnt] = v; dist[cnt] = w; dir[cnt] = d; } void ins_edge( int u, int v, int w) { add_edge(u, v, w); add_edge(v, u, w, false ); } using ll = long long ; using pii = std::pair<ll, int >; int n; std::vector< int > V; ll d[maxn]; int src[maxn]; bool vis[maxn]; void dij() { memset (d, 0x1f, sizeof (d)); std::priority_queue<pii, std::vector<pii>, std::greater<pii> > Q; for (auto p : V) { d[p] = 0; src[p] = p; Q.push(std::make_pair(0LL, p)); } while (!Q.empty()) { int u = Q.top().second; Q.pop(); if (vis[u]) continue ; vis[u] = true ; for ( int i = first[u]; i; i = next[i]) { int v = to[i]; if (d[u] + (ll(dist[i])) < d[v]) { d[v] = d[u] + (ll(dist[i])); src[v] = src[u]; Q.push(std::make_pair(d[v], v)); } } } } int p[maxn], rk[maxn]; int get_fa( int x) { if (p[x] == x) { return x; } else { return (p[x] = get_fa(p[x])); } } void link_set( int x, int y) { if (rk[x] > rk[y]) std::swap(x, y); p[x] = y; if (rk[x] == rk[y]) rk[y] ++; } void merge_set( int x, int y) { x = get_fa(x); y = get_fa(y); if (x != y) link_set(x, y); } bool is_same( int x, int y) { return (get_fa(x) == get_fa(y)); } void init_set() { for ( int i = 1; i <= n; i ++) { p[i] = i; } } struct Edge { int u, v; ll w; Edge( int a = 0, int b = 0, ll c = 0) { u = a; v = b; w = c; } bool operator <( const Edge &res) const { return w < res.w; } }; int m; Edge E[maxm]; int ecnt; void process() { dij(); ecnt = 0; for ( int i = 1; i <= n; i ++) { for ( int j = first[i]; j; j = next[j]) { int v = to[j]; if (dir[j] && src[i] != src[v]) { E[++ ecnt] = Edge(src[i], src[v], (ll(dist[j])) + d[i] + d[v]); } } } std::sort(E + 1, E + 1 + ecnt); } bool ans[maxm]; void solve() { int q; scanf ( "%d" , &q); init_set(); int cur = 0; std::vector<std::pair<Edge, int > > Q; for ( int i = 1; i <= q; i ++) { int u, v; ll w; scanf ( "%d%d%lld" , &u, &v, &w); Q.push_back(std::make_pair(Edge(u, v, w), i)); } std::sort(Q.begin(), Q.end()); for (auto x : Q) { Edge e = x.first; while (cur < ecnt && E[cur + 1].w <= e.w) { cur ++; merge_set(E[cur].u, E[cur].v); } ans[x.second] = is_same(e.u, e.v); } for ( int i = 1; i <= q; i ++) { if (ans[i]) { puts ( "TAK" ); } else { puts ( "NIE" ); } } } int main() { int s; scanf ( "%d%d%d" , &n, &s, &m); for ( int i = 1; i <= s; i ++) { int x; scanf ( "%d" , &x); V.push_back(x); } for ( int i = 1; i <= m; i ++) { int u, v, w; scanf ( "%d%d%d" , &u, &v, &w); ins_edge(u, v, w); } process(); solve(); return 0; } |
[BZOJ 2662]冻结
又是一道分层图最短路水题……
我估计会卡SPFA(或许可能不卡?),所以再次写了pb_ds优化Dijkstra。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | /************************************************************** Problem: 2662 User: danihao123 Language: C++ Result: Accepted Time:4 ms Memory:868 kb ****************************************************************/ #include <cstdio> #include <cctype> #include <cstring> #include <utility> #include <ext/pb_ds/priority_queue.hpp> #include <bitset> #include <algorithm> using namespace std; const int maxn=51,maxk=51,maxm=2005; int cnt=0; int first[maxn]; int to[maxm],next[maxm]; int dist[maxm]; inline void Add_Edge( int x, int y, int z){ cnt++; next[cnt]=first[x]; first[x]=cnt; to[cnt]=y; dist[cnt]=z; } int d[maxn][maxk]; bitset<maxn> vis[maxk]; struct Node{ int x,k,d; bool operator <( const Node& itt) const { return d<itt.d; } bool operator >( const Node& itt) const { return d>itt.d; } }; typedef __gnu_pbds::priority_queue<Node,greater<Node> > Heap; Heap::point_iterator ite[maxn][maxk]; Heap Q; int n,k; inline void relax( int x, int y, int p){ d[x][y]=p; if (ite[x][y]!=0) Q.modify(ite[x][y],(Node){x,y,p}); else ite[x][y]=Q.push((Node){x,y,p}); } int dij(){ register int i,u,v,ans=0x7f7f7f7f; memset (d,0x7f, sizeof (d)); d[1][0]=0; ite[1][0]=Q.push((Node){1,0,0}); while (!Q.empty()){ u=Q.top().x; v=Q.top().k; Q.pop(); if (vis[u][v]) continue ; vis[u][v]= true ; for (i=first[u];i;i=next[i]){ if (v<k){ if (d[to[i]][v+1]>(d[u][v]+dist[i]/2)){ relax(to[i],v+1,d[u][v]+dist[i]/2); } } if (d[to[i]][v]>d[u][v]+dist[i]){ relax(to[i],v,d[u][v]+dist[i]); } } } for (i=0;i<=k;i++) ans=min(ans,d[n][i]); return ans; } // I/O优化 inline int readint(){ char c= getchar (); register int x=0; while (! isdigit (c)) c= getchar (); while ( isdigit (c)){ x=x*10+c- '0' ; c= getchar (); } return x; } int bf[10]; inline void writeint( int x){ register int p=0; if (x==0){ bf[p++]=0; } else { while (x){ bf[p++]=x%10; x/=10; } } for ( register int i=p-1;i>=0;i--) putchar ( '0' +bf[i]); } int main(){ int m; register int i,u,v,d; n=readint(); m=readint(); k=readint(); for (i=1;i<=m;i++){ u=readint(); v=readint(); d=readint(); Add_Edge(u,v,d); Add_Edge(v,u,d); } writeint(dij()); putchar ( '\n' ); return 0; } |
[BZOJ 2763]飞行路线
分层图最短路处女作TAT
很明显要求你求一个分层图上的最短路。不过没必要把分层图构出来,手写转移即可。还有卡SPFA是怎么回事?出题人你粗来我保证不打死你……
然而沉迷pb_ds,不能自拔。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | /************************************************************** Problem: 2763 User: danihao123 Language: C++ Result: Accepted Time:268 ms Memory:3136 kb ****************************************************************/ #include <cstdio> #include <queue> #include <algorithm> #include <utility> #include <cstring> #include <cctype> #include <ext/pb_ds/priority_queue.hpp> using namespace std; const int maxn=10001,maxm=100001,maxk=11; typedef pair< int , int > pii; int first[maxn]; int next[maxm],to[maxm],dist[maxm]; int graph_cnt=0; inline void Add_Edge( int u, int v, int d){ graph_cnt++; next[graph_cnt]=first[u]; first[u]=graph_cnt; to[graph_cnt]=v; dist[graph_cnt]=d; } struct Node{ pii pnt; int d; bool operator <( const Node& x) const { return d<x.d; } bool operator >( const Node& x) const { return d>x.d; } }; typedef __gnu_pbds::priority_queue<Node,greater<Node> > Heap; Heap::point_iterator ite[maxn][maxk]; Heap Q; int n,k; bool vis[maxn][maxk]; int d[maxn][maxk]; inline void relax( int u, int v, int di){ d[u][v]=di; if (ite[u][v]!=0) Q.modify(ite[u][v],(Node){make_pair(u,v),di}); else ite[u][v]=Q.push((Node){make_pair(u,v),di}); } int Dijkstra( int s, int t){ register int i,u,v; pii temp; memset (d,0x7f, sizeof (d)); d[s][0]=0; ite[s][0]=Q.push((Node){make_pair(s,0),0}); while (!Q.empty()){ temp=Q.top().pnt; Q.pop(); u=temp.first; v=temp.second; if (vis[u][v]) continue ; vis[u][v]= true ; for (i=first[u];i;i=next[i]){ if (v<k){ if (d[u][v]<d[to[i]][v+1]){ relax(to[i],v+1,d[u][v]); } } if (d[u][v]+dist[i]<d[to[i]][v]){ relax(to[i],v,d[u][v]+dist[i]); } } } register int ans=0x7f7f7f7f; for (i=0;i<=k;i++) ans=min(ans,d[t][i]); return ans; } int main(){ int m,s,t,u,v,d; register int i; scanf ( "%d%d%d%d%d" ,&n,&m,&k,&s,&t); for (i=1;i<=m;i++){ scanf ( "%d%d%d" ,&u,&v,&d); Add_Edge(u,v,d); Add_Edge(v,u,d); } printf ( "%d\n" ,Dijkstra(s,t)); return 0; } |
[BZOJ 4152]The Captain
这题初看有些棘手。但是毕竟是最短路,这样的边,大可以分成两条边来建,于是乎min就形同虚设了。并且我们可以看到这样建图有一个好处:跨越若干点的方案可以一定可以分成图上的若干边。问题大为简化,迎刃而解。
但这提有个丧病的地方:卡SPFA。加了一些优化照样挂。所以我一气之下写了可并堆优化的Dijkstra :)当然可并堆用的是pb_ds辣。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | /************************************************************** Problem: 4152 User: danihao123 Language: C++ Result: Accepted Time:4888 ms Memory:17412 kb ****************************************************************/ #include <cstdio> #include <algorithm> #include <cstring> #include <utility> #include <ext/pb_ds/priority_queue.hpp> #include <cctype> #include <bitset> #ifdef DEBUG #include <cassert> #endif using namespace std; const int maxn=200001; int n; inline int abs ( int x){ return x<0?-x:x; } int first[maxn]; int next[maxn*4],to[maxn*4],dist[maxn*4]; int graph_cnt=0; inline void Add_Edge( int x, int y, int d){ graph_cnt++; next[graph_cnt]=first[x]; first[x]=graph_cnt; to[graph_cnt]=y; dist[graph_cnt]=d; } int d[maxn]; bitset<maxn> vis; typedef pair< int , int > my_pair; typedef __gnu_pbds::priority_queue<my_pair,greater<my_pair> > Heap; Heap::point_iterator ite[maxn]; Heap Q; int dij(){ register int i,u; memset (d,0x7f, sizeof (d)); d[1]=0; ite[1]=Q.push(make_pair(0,1)); while (!Q.empty()){ u=Q.top().second; Q.pop(); if (vis[u]) continue ; vis[u]= true ; for (i=first[u];i;i=next[i]){ if (d[to[i]]>(dist[i]+d[u])){ d[to[i]]=dist[i]+d[u]; if (ite[to[i]]!=0) Q.modify(ite[to[i]],make_pair(d[to[i]],to[i])); else ite[to[i]]=Q.push(make_pair(d[to[i]],to[i])); } } } return d[n]; } int pr[maxn][2]; int order1[maxn],order2[maxn]; int cmp1( const int i, const int j){ return pr[i][0]<pr[j][0]; } int cmp2( const int i, const int j){ return pr[i][1]<pr[j][1]; } // I/O优化 inline int readint(){ char c= getchar (); register int x=0; while (! isdigit (c)) c= getchar (); while ( isdigit (c)){ x=x*10+c- '0' ; c= getchar (); } return x; } int main(){ register int i; n=readint(); for (i=1;i<=n;i++){ pr[i][0]=readint(); pr[i][1]=readint(); order1[i]=i; order2[i]=i; } sort(order1+1,order1+1+n,cmp1); sort(order2+1,order2+1+n,cmp2); for (i=1;i<=n;i++){ if (i!=1){ Add_Edge(order1[i],order1[i-1],pr[order1[i]][0]-pr[order1[i-1]][0]); Add_Edge(order2[i],order2[i-1],pr[order2[i]][1]-pr[order2[i-1]][1]); } if (i!=n){ Add_Edge(order1[i],order1[i+1],pr[order1[i+1]][0]-pr[order1[i]][0]); Add_Edge(order2[i],order2[i+1],pr[order2[i+1]][1]-pr[order2[i]][1]); } } printf ( "%d\n" ,dij()); return 0; } |