CF Round 620 Div2 EF题解

E 1-Trees and Queries

给定一棵树,每次独立询问要求x,y之间连一条边(本来不相连),从a走到b路径长度能否恰好等于k(所有点可以无限次重复经过)

思路

可以发现,如果两点间最短路径长度≤k时,路径长度能否恰好为k只和(k-路径长度)的奇偶性相关。
所以,对于每次询问,判断三种情况:
1.a-b
2.a-x-y-b
3.a-y-x-b
只要其中有一种满足(k-其最短路径长度)为偶数,既满足,反之则不满足。
至于求两点间最短路径,只需差分思想+lca即可。

Code

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=100007;
int n,dep[maxn],fa[18][maxn];
int q,xx,yy,aa,bb,k;
vector <int> a[maxn];
void dfs(int u,int p) {
	fa[0][u]=p;
	for (int i=0; i<a[u].size(); i++) {
		int v=a[u][i];
		if (v==p) continue;
		dep[v]=dep[u]+1;
		dfs(v,u);
	}
}
int lca(int x,int y) {
	if (dep[x]<dep[y]) swap(x,y);
	if (dep[x]>dep[y]) 
		for (int i=17; i>=0; i--) if (dep[x]-dep[y]>=(1<<i)) 
			x=fa[i][x];
	if (x==y) return x;
	for (int i=17; i>=0; i--) if (fa[i][x]!=fa[i][y]) {
		x=fa[i][x];
		y=fa[i][y];
	}	
	return fa[0][x];
}
int dis(int x,int y) {
	return dep[x]+dep[y]-2*dep[lca(x,y)];
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n;
	for (int i=1; i<n; i++){
		int u,v;
		cin>>u>>v;
		a[u].push_back(v);
		a[v].push_back(u);
	}
	dfs(1,0);
	for (int i=1; i<=17; i++) 
		for (int j=1; j<=n; j++) 
		fa[i][j]=fa[i-1][fa[i-1][j]];
	cin>>q;
	while (q-->0) {
		cin>>xx>>yy>>aa>>bb>>k;
		bool now=false;
		if (dis(aa,bb)<=k && (k-dis(aa,bb))%2==0) now=true;
		if (dis(aa,xx)+dis(yy,bb)+1<=k && (k-(dis(aa,xx)+dis(yy,bb)+1))%2==0) now=true;
		if (dis(aa,yy)+dis(xx,bb)+1<=k && (k-(dis(aa,yy)+dis(xx,bb)+1))%2==0) now=true;
		if (now) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

F Animal Observation

Gildong要观察动物,共有n天,每天从1-m依次有m个点,每个点的动物数量给定。
1-n天中的奇数天在某点设立一个红相机,每天可以拍到连续的k个点的动物,延续两天,即覆盖一个2*k的矩形。
偶数天设立蓝相机,规则与红相机相同。
若第n天设立相机,则只照一天,现问如何安排相机可以拍到最多的动物。

思路

首先红蓝不用去考虑,反正就是每天新增一个相机。
然后因为这里要求目标值最大以及状态无后效性,容易想到dp
f[i][j]表示第i天在第j个位置(左起点)放置完一个相机后拍到的最多的动物数。(sum代表每一天的前缀和)
可以得到转移方程
f[i][j]=sum[i+1][j+k-1]-sum[i+1][j-1]+
max(
f[i-1][x]+sum[i][j+k-1]-sum[i][j-1]   1≤x≤j-k 或 j+k≤x≤m-k+1
f[i-1][x]+sum[i][j+k-1]-sum[i][x+k-1]   j-k+1≤x≤j
f[i-1][x]+sum[i][x-1]-sum[i][j-1]   j+1≤x≤m-k+1
)
第一种情况由于只和f[i-1][x]大小有关,所以可以在上一天预处理出f的前缀以及后缀最大值。
第二、三种情况在easy version中因为k≤20所以可以暴力解决。
在hard version中就需要数据结构进行维护,这里的下标条件很像滑动窗口,所以可以考虑用两个单调队列进行dp优化
最后时间复杂度O(nm)。
Notice:用deque获取front()或back()前一定要判断empty(),否则就会RE。

Code

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int maxn=57;
const int maxm=20007;
int n,m,k,s[maxn][maxm],f[maxn][maxm];
int ml[maxm],mr[maxm],ans,tmp;
deque <int> q1,q2;
int main() {
	ios::sync_with_stdio(false);
	cin>>n>>m>>k;
	for (int i=1; i<=n; i++) 
		for (int j=1; j<=m; j++) {
			cin>>tmp;
			s[i][j]=s[i][j-1]+tmp;
		}
	for (int i=1; i<=m-k+1; i++) 
		f[1][i]=s[1][i+k-1]-s[1][i-1]+s[2][i+k-1]-s[2][i-1];
	for (int i=1; i<=m-k+1; i++) ml[i]=max(ml[i-1],f[1][i]);
	for (int i=m-k+1; i>0; i--) mr[i]=max(mr[i+1],f[1][i]);
	for (int i=2; i<=n; i++) {
		for (int j=1; j<=m-k+1; j++) {
			f[i][j]=s[i+1][j+k-1]-s[i+1][j-1];
			int add_v=0;
			if (j>k) add_v=max(add_v,ml[j-k]+s[i][j+k-1]-s[i][j-1]);
			if (j+k<=m-k+1) add_v=max(add_v,mr[j+k]+s[i][j+k-1]-s[i][j-1]); 
			while (!q1.empty() && 
		       (f[i-1][q1.back()]-s[i][q1.back()+k-1])<=(f[i-1][j]-s[i][j+k-1])
				  ) q1.pop_back();
			q1.push_back(j);
			while (!q1.empty() && q1.front()<j-k+1) q1.pop_front();
			if (!q1.empty())
				add_v=max(add_v,f[i-1][q1.front()]+s[i][j+k-1]-s[i][q1.front()+k-1]);
			f[i][j]+=add_v;
		}
		for (int j=m-k+1; j>0; j--) {
			if (j<m-k+1) if (!q2.empty())
				f[i][j]=max(f[i][j],f[i-1][q2.front()]+
									s[i][q2.front()-1]-
									s[i][j-1]+s[i+1][j+k-1]-s[i+1][j-1]
							);
			while (!q2.empty() && (f[i-1][q2.back()]+s[i][q2.back()-1])<=
								  (f[i-1][j]+s[i][j-1])	
				  ) q2.pop_back();
			q2.push_back(j);
			while (!q2.empty() && q2.front()>j+k-2) q2.pop_front();
		}	
		while (!q1.empty()) q1.pop_front();
		while (!q2.empty()) q2.pop_front();
		for (int j=1; j<=m-k+1; j++) ml[j]=max(ml[j-1],f[i][j]);
		for (int j=m-k+1; j>0; j--) mr[j]=max(mr[j+1],f[i][j]);
	}
	for (int i=1; i<=m-k+1; i++) ans=max(ans,f[n][i]);
	cout<<ans<<endl;
	return 0;
}
posted @ 2020-02-22 16:25  yich  阅读(95)  评论(0)    收藏  举报