「Wdoi-1.5」旅人 1977 题解
Solution
然而并没有做出来,听wy讲的。
我们考虑倒着来,那么我们只需要记录下哪些在后面会 pushdown ,这样这条边所增加的节点的权值就会增加子树内需 pushdown 的节点个数乘上增加的值。
然后注意到需 pushdown 的表达状态很少,所以我们可以进行最短路。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 205
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
int n,m,K,S,T,tot,mp[(1 << 25) + 5],tur[17005];
#define MAXK 35
int cnt,dfn[MAXK << 2],tor[MAXK << 2],dis[MAXK << 2];
void build (int x,int l,int r){
if (l == r) return ;
int mid = l + r >> 1;
dfn[x] = ++ cnt,tor[cnt] = x,dis[x] |= (1 << dfn[x] - 1);
dis[x << 1] |= dis[x],dis[x << 1 | 1] |= dis[x],build (x << 1,l,mid),build (x << 1 | 1,mid + 1,r);
return ;
}
int pnt[MAXK << 2],siz[17005][MAXN];
void dfs (int now){
if (now == 0){
int sta = 0;
for (Int i = 1;i <= cnt;++ i) if (pnt[i]) sta |= (1 << i - 1);
if (!mp[sta]){
mp[sta] = ++ tot,tur[tot] = sta;
for (Int i = 1;i <= cnt;++ i) siz[tot][i] = pnt[i];
for (Int i = cnt;i >= 1;-- i) siz[tot][i] += siz[tot][dfn[tor[i] << 1]] + siz[tot][dfn[tor[i] << 1 | 1]];
}
return ;
}
dfs (now - 1);
if (!pnt[now]){
int t = tor[now],fuc[MAXK << 2] = {};
for (Int i = 1;i <= cnt;++ i) fuc[i] = pnt[i];
while (t) pnt[dfn[t]] = 1,t >>= 1;
dfs (now - 1);
for (Int i = 1;i <= cnt;++ i) pnt[i] = fuc[i];
}
}
#define pii pair<int,int>
#define se second
#define fi first
int nsta;
vector <int> S1[MAXK][MAXK];
void fuckit (int x,int l,int r,int ql,int qr){
if (l >= ql && r <= qr){
S1[ql][qr].push_back (x);
return ;
}
int mid = l + r >> 1;
if (ql <= mid) fuckit (x << 1,l,mid,ql,qr);
if (qr > mid) fuckit (x << 1 | 1,mid + 1,r,ql,qr);
}
void init (){
for (Int ql = 1;ql <= K;++ ql)
for (Int qr = ql;qr <= K;++ qr) fuckit (1,1,K,ql,qr);
}
int modify (int ql,int qr,int sta,int v){
int val = 0;
for (Int x : S1[ql][qr]) val += (siz[sta][dfn[x]] + 1) * v,nsta |= dis[x >> 1];
return val;
}
struct edge{
int v,l,r,w;
};
vector <edge> g[MAXN];
#define trp pair<int,pii>
int ans,dist[MAXN][17005];bool vis[MAXN][17005];
priority_queue <trp,vector <trp>,greater <trp> > q;
void Dijkstra (int st,int ed){
memset (dist,127,sizeof (dist)),q.push ({dist[st][1] = 0,{st,1}});
while (!q.empty()){
trp it = q.top();q.pop ();int u = it.se.fi,sta = it.se.se,dis = it.fi;
if (vis[u][sta]) continue;
vis[u][sta] = 1;
if(u == ed) break;
if (ans < dist[u][sta]) continue;
for (edge to : g[u]){
int v = to.v,l = to.l,r = to.r,w = to.w;
nsta = tur[sta];int val = modify (l,r,sta,w);nsta = mp[nsta];
if (dist[v][nsta] > dis + val){
dist[v][nsta] = dis + val;
if (v == ed) chkmin (ans,dist[v][nsta]);
q.push ({dist[v][nsta],{v,nsta}});
}
}
}
}
signed main(){
read (n,m,K,S,T),build (1,1,K),dfs (cnt),init ();
for (Int i = 1,u,v,l,r,w;i <= m;++ i)
read (u,v,l,r,w),g[v].push_back (edge{u,l,r,w});
ans = 1e9,Dijkstra (T,S),write (ans),putchar ('\n');
return 0;
}