题解 午餐

传送门

貌似超脑少年团原题,先咕了
好吧不是原题,但题意差不多

第一次写这种限制类的题,确实很有思维难度
需要考虑的情况很多,直接大力分情况讨论没什么用,必须从最本质的地方分情况讨论才行
而且如果一个这样的题没有大样例还不知道怎么写这题的拍应该就可以直接跑路了

对于本题,首先如果没有某些人一定没有感染的限制,直接尽量感染一遍,看有没有感染不到的人就行
具体地,用一个最短路处理出 \(h[i]\) 表示第一个人在不考虑其它限制的情况下最早什么时候可能被感染
部分分check一下有没有应该但未被感染的人就行了

然后正解:
现在考虑怎么加上一些人不能被感染的限制
发现等价于给每个人加上一个 \(lim[i]\) 代表这个人在时刻 \(lim[i]\) 及之前不能被感染
可以先从未被感染的人开始最短路求出 \(lim\)
然后考虑从点1开始在带限制的情况下求出 \(h\)
还是正常dijkstra,如果能更新就把边权设为要更新的值
但是重点考虑不能更新的情况,没考虑这个调了一下午
两种情况:不合法和不是最优
之前做法错误在于这两种情况直接设成 \(e[i].l\)
但实际上不合法(\(lim[v]+1 > e[i].r\))必须取 \(e[i].l\) 而不能是其它的,否则 \(u\) 可能提前更新 \(v\)
不是最优应该把边权直接设为这个值,否则 \(v\) 可能会提前更新 \(u\)
复杂度 \(O(mlogn)\)

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 2139062143
#define N 200010
#define ll long long
#define reg register int
#define fir first
#define sec second
#define make make_pair
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int sit[N];

namespace force{
	int size=1, sta[20], top, mday;
	bool vis[20];
	struct edge{int l, r, tim, id;}e[N];
	int mp[20][20];
	bool check() {
		top=0;
		sta[++top]=1;
		memset(vis, 0, sizeof(vis));
		vis[1]=1;
		for (int day=1; day<=mday; ++day) {
			for (int i=1; i<=top; ++i) {
				for (int j=1; j<=n; ++j) if (mp[i][j] && e[mp[i][j]].tim==day) {
					if (!vis[j]) vis[j]=1, sta[++top]=j;
				}
			}
		}
		for (int i=1; i<=n; ++i)
			if (sit[i]==1) {
				if (!vis[i]) return 0;
			}
			else if (sit[i]==-1) {
				if (vis[i]) return 0;
			}
		for (int i=2; i<=m*2; i+=2)
			printf("%d\n", e[i].tim);
		exit(0);
	}
	void dfs(int u) {
		if (u>m*2) {
			check();
			return ;
		}
		for (int i=e[u].l; i<=e[u].r; ++i) {
			e[u].tim=e[u^1].tim=i;
			dfs(u+2);
		}
	}
	void solve() {
		for (int i=1,u,v,l,r; i<=m; ++i) {
			u=read(); v=read(); l=read(); r=read();
			mday=max(mday, r);
			e[++size].l=l; e[size].r=r; e[size].id=size; mp[u][v]=size;
			e[++size].l=l; e[size].r=r; e[size].id=size; mp[v][u]=size;
		}
		for (int i=1; i<=n; ++i) sit[i]=read();
		dfs(2);
		puts("Impossible");
		exit(0);
	}
}

namespace task{
	int h[N], head[N], size=1, sit[N], lim[N];
	bool vis[N];
	struct edge{int from, to, next, l, r, tim;}e[N<<1];
	inline void add(int s, int t, int l, int r) {e[++size].to=t; e[size].from=s; e[size].tim=INF; e[size].l=l; e[size].r=r; e[size].next=head[s]; head[s]=size;}
	void dij1() {
		memset(vis, 0, sizeof(vis));
		queue<int> q;
		for (int i=1; i<=n; ++i) if (sit[i]==-1) lim[i]=INF, q.push(i), vis[i]=1;
		int u;
		while (q.size()) {
			u=q.front(); q.pop();
			vis[u]=0;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (lim[u]>=e[i].r) {
					if (lim[v]<e[i].l) {
						lim[v]=e[i].l;
						if (!vis[v]) q.push(v), vis[v]=1;
					}
				}
			}
		}
	}
	void dij2(int dis[], int s) {
		memset(dis, 127, sizeof(int)*(n+5));
		memset(vis, 0, sizeof(vis));
		priority_queue< pair<int, int> > q;
		dis[s]=lim[s]+1;
		q.push(make(-dis[s], s));
		pair<int, int> u;
		while (q.size()) {
			u=q.top(); q.pop();
			//cout<<"u: "<<u.fir<<' '<<u.sec<<endl;
			if (vis[u.sec]) continue;
			vis[u.sec]=1;
			for (int i=head[u.sec],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (dis[v]>max(max(dis[u.sec], e[i].l), lim[v]+1) && max(max(dis[u.sec], e[i].l), lim[v]+1)<=e[i].r) {
					dis[v] = max(max(dis[u.sec], e[i].l), lim[v]+1);
					q.push(make(-dis[v], v));
					e[i].tim=min(e[i].tim, dis[v]);
					e[i^1].tim=min(e[i^1].tim, dis[v]);
				}
				else {
					if (max(max(dis[u.sec], e[i].l), lim[v]+1)<=e[i].r) e[i].tim=e[i^1].tim=max(max(dis[u.sec], e[i].l), lim[v]+1);
					else e[i].tim=e[i^1].tim=e[i].l;
				}
			}
		}
	}
	void solve() {
		memset(head, -1, sizeof(head));
		for (int i=1,u,v,l,r; i<=m; ++i) {
			u=read(); v=read(); l=read(); r=read();
			add(u, v, l, r); add(v, u, l, r);
		}
		for (int i=1; i<=n; ++i) sit[i]=read();
		dij1(); dij2(h, 1);
		// cout<<"lim: "; for (int i=1; i<=n; ++i) cout<<lim[i]<<' '; cout<<endl;
		// cout<<"h: "; for (int i=1; i<=n; ++i) cout<<h[i]<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) assert(h[i]==INF || h[i]>lim[i]);
		if (h[1]!=1) {puts("Impossible"); exit(0);}
		for (int i=1; i<=n; ++i) if (sit[i]==1 && h[i]==INF) {puts("Impossible"); exit(0);}
		for (int i=2; i<=m*2; i+=2) {
			// if (max(lim[e[i].from], lim[e[i].to])<=min(h[e[i].from], h[e[i].to])) {puts("Impossible"); exit(0);}
			// printf("%d\n", e[i].tim==INF?min(max( max(lim[e[i].from], lim[e[i].to])+1, e[i].l), e[i].r):e[i].tim);
			printf("%d\n", e[i].tim==INF?e[i].l:e[i].tim);
			// else if (max(max(max(h[e[i].from], h[e[i].to]), max(lim[e[i].from], lim[e[i].to])), e[i].l)>e[i].r) {puts("Impossible"); exit(0);}
			// else printf("%d\n", min(max(max(h[e[i].from], h[e[i].to]), e[i].l), e[i].r));
			// else printf("%d\n", min(max( min(max(h[e[i].from], lim[e[i].to]+1), max(h[e[i].to], lim[e[i].from]+1)) , e[i].l), e[i].r));
		}
		exit(0);
	}
}

signed main()
{
	#ifdef LOCAL
	freopen("input", "r", stdin);
	freopen("user_out", "w", stdout);
	#else 
	freopen("lunch.in", "r", stdin);
	freopen("lunch.out", "w", stdout);
	#endif
	
	n=read(); m=read();
	//force::solve();
	//if (n<=15 && m<=15) force::solve();
	//else puts("Impossible");
	task::solve();
	
	return 0;
}
posted @ 2021-09-14 21:29  Administrator-09  阅读(11)  评论(0编辑  收藏  举报