Live2D

「Wdoi-1.5」旅人 1977 题解

link

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;
}
posted @ 2022-02-08 17:32  Dark_Romance  阅读(39)  评论(0编辑  收藏  举报