[Contest on 2020.12.1] ZZH的游戏

( ext{Description})

传送门

( ext{Solution})

可以先考虑二分一个答案,发现可以先固定一个端点,另一个点拓展与它相连通的小于等于那个点的点,然后更新另一个点连通块的最小值,再用先开始的端点拓展…当无法拓展且需要新加入的点与另一边的最小值点相加大于二分的答案,而且两边的 (1) 都没被包含就不合法,这个过程可以用堆来维护,时间复杂度 (mathcal O(nlog ^2n))

其实可以省掉二分,我们把初始答案设为 (s+t),按上面的方法直接拓展即可。时间复杂度 (mathcal O(nlog n))

其实也可以省掉堆,因为这个题目有一个性质:权值是连续的 ([1,n]) 区间内的数。

对于每一个点我们有两个标记:(vis,in),分别表示旁边是否已经有进块的点,是否在连通块。一边找到最小值后,其实不用直接赋值,可以将最小值线一步步下挪,将另一边的最大值线一步步上挪,尝试拓展最大值线代表的点入块,这样就是 (mathcal O(n)) 的?

( ext{Code})

#include <cstdio>

#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
#define print(x,y) write(x),putchar(y)

template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}

const int maxn=1e6+5;

int n,lim[2],ans,s,t,lims,limt,mins,mint;
bool vis[maxn][2],In[maxn][2];
int cnt[2],head[maxn][2],nxt[maxn<<1][2],to[maxn<<1][2];

void addEdge(int u,int v,bool op) {
	nxt[++cnt[op]][op]=head[u][op],to[cnt[op]][op]=v,head[u][op]=cnt[op];
	nxt[++cnt[op]][op]=head[v][op],to[cnt[op]][op]=u,head[v][op]=cnt[op];
}

void dfss(int u) {
	In[u][0]=1;
	if(u<mins) mins=u;
	for(int i=head[u][0];i;i=nxt[i][0]) {
		int v=to[i][0];
		if(!In[v][0]) {
			if(lims<v) vis[v][0]=1;
			else dfss(v);
		}
	}
}

void dfst(int u) {
	In[u][1]=1;
	if(u<mint) mint=u;
	for(int i=head[u][1];i;i=nxt[i][1]) {
		int v=to[i][1];
		if(!In[v][1]) {
			if(limt<v) vis[v][1]=1;
			else dfst(v);
		}
	}
}

int main() {
	int u,v;
	for(int T=read(9);T;--T) {
		n=read(9); cnt[0]=cnt[1]=0;
		for(int i=1;i<=n;++i) head[i][0]=head[i][1]=In[i][0]=In[i][1]=vis[i][0]=vis[i][1]=0;
		for(int i=1;i<n;++i) u=read(9),v=read(9),addEdge(u,v,0);
		for(int i=1;i<n;++i) u=read(9),v=read(9),addEdge(u,v,1);
		s=read(9),t=read(9); lims=mins=s,mint=limt=t;
		vis[s][0]=vis[t][1]=1; ans=s+t;
		while(233) {
			if(lims<=n&&vis[lims][0]&&(!In[lims][0])) dfss(lims);
			if(limt<=n&&vis[limt][1]&&(!In[limt][1])) dfst(limt);
			if(s==mins&&t==mint) break;
			if(s>mins) --s,++limt;
			if(t>mint) --t,++lims;
		}
		while(!In[1][0]||In[1][1]==0) {
			++ans; ++lims,++limt;
			while(233) {
				if(lims<=n&&vis[lims][0]&&(!In[lims][0])) dfss(lims);
				if(limt<=n&&vis[limt][1]&&(!In[limt][1])) dfst(limt);
				if(s==mins&&t==mint) break;
				if(s>mins) --s,++limt;
				if(t>mint) --t,++lims;
			}
		}
		print(ans,'
');
	}
	return 0;
} 
原文地址:https://www.cnblogs.com/AWhiteWall/p/14069789.html