#并查集,单调栈#美团2018年CodeM大赛-决赛 C-Traffic

题目


分析

首先如果枚举起点\(i\),点\(i\)到点\(j\)(i<j)的距离跳到点\(k\)(k<i)一定不优,所以可以先处理这种情况,
用单调栈维护\(dp\)单调递增,并且如果栈顶不能跳到当前点所能一次跳到的最前方那么就弹出,\(dp\)值就是栈元素个数加1
如果往前跳,按照刚才\(dp\)值由小到大更新往前跳的答案,并用并查集维护每个位置只能被更新一次,总时间复杂度\(O(n^2)\)
严格意义上来说,并查集路径压缩要加上\(logn\)的时间复杂度,但由于常数比较小可以忽略不计


代码

#include <cstdio>
#include <cctype>
#include <vector>
#define rr register
using namespace std;
const int N=6011; vector<int>K[N];
int n,ans,a[N],b[N],st[N],top,dp[N],f[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
signed main(){
	n=iut(),a[1]=b[1]=1;
	for (rr int i=2;i<=n;++i) a[i]=iut();
	for (rr int i=2;i<=n;++i) b[i]=iut();
	for (rr int i=1;i<=n;++i){
		for (rr int j=0;j<=n;++j) f[j]=j,K[j].clear(),dp[j]=n+1;
		st[top=0]=i,dp[i]=0,K[0].push_back(i);
		for (rr int j=i+1;j<=n;++j){
			while (top>0&&st[top-1]>=b[j]) --top;
			dp[j]=top+1,st[++top]=j,K[dp[j]].push_back(j); 
		}
		for (rr int j=0;j<=n;++j)
		for (rr int p=0;p<K[j].size();++p){
			rr int x=K[j][p];
			for (rr int now=getf(x-1);now>=a[x];now=getf(now-1)){
				if (dp[now]>j+1) dp[now]=j+1,K[j+1].push_back(now);
				f[now]=now-1;
			}
		}
		for (rr int j=1;j<=n;++j) ans^=(i+j)*dp[j];
	}
	return !printf("%d",ans);
}
posted @ 2020-08-11 14:41  lemondinosaur  阅读(109)  评论(0编辑  收藏  举报