ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「CEOI2020」春季大扫除 题解

2021-08-27 08:32:22  阅读:167  来源: 互联网

标签:100005 结点 int 题解 tr 叶子 CEOI2020 son 大扫除


题意

\(~~~~\) 给出若干次询问,每次询问将对若干个点增加叶子结点(同一个点可能加多次),定义一组叶子结点匹配的权值为这两点间路径经过的边数,求最小的匹配权值。
\(~~~~\) \(1\leq n\leq 10^5,1\leq \sum D_i \leq 10^5\)

本文版权归 Azazel 与博客园共有,欢迎转载,但需保留此声明,并给出原文地址,谢谢合作。

原文地址:https://www.cnblogs.com/Azazel/p/15192326.html

题解

\(~~~~\) 首先,叶子结点必须是偶数时才有解,因为奇数时至少会存在一个叶子其到父亲的边不能被清扫。

\(~~~~\) 接下来考虑一棵子树:

  • 当子树内叶子结点为奇数时,该子树根节点到父亲的边会被清扫一次;
  • 当子树内叶子结点为偶数时,该子树根节点到父亲的边会被清扫两次;

\(~~~~\) 考虑证明这个结论的正确性:每个点(除去钦定的根节点)到父亲的边都应该被清扫至少一次。当子树内只剩一个叶子结点未匹配时,外界也会有奇数个叶子结点供该点匹配,偶数同理。当每个点(除去钦定的根节点)到父亲的边都被清扫,我们就可以认为整棵树被清扫了。

\(~~~~\) 以上是一个 \(\mathcal{o(nq)}\) 的做法,考虑我们需要的信息只有每个点子树内的叶子结点数量 \(\bmod 2\),故我们用树剖维护,对于某个点若其为叶子结点则不管,否则将该点到根节点的路径上所有点的点权 \(\oplus 1\) ,最后统计除了 \(1\) 之外所有点的点权和。由于 \(1\) 的点权必定为 \(0\),所以统计整棵树的点权和即可。

代码

查看代码
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
int n,q,m;
int siz[100005],dfn[100005],top[100005],sizLeaf[100005];
int dep[100005],fa[100005],To[100005],Times,son[100005],deg[100005];
bool IsLeaf[100005];
vector <int> G[100005];
void dfs1(int u,int Fa)
{
	sizLeaf[u]=IsLeaf[u];fa[u]=Fa;
	siz[u]=1;dep[u]=dep[Fa]+1;
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==Fa) continue;
		dfs1(v,u);
		siz[u]+=siz[v];sizLeaf[u]=(sizLeaf[u]+sizLeaf[v])%2;
		if(siz[v]>siz[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int T)
{
	top[u]=T;dfn[u]=++Times;To[Times]=u;
	if(!son[u]) return; dfs2(son[u],T);
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==fa[u]||v==son[u]) continue;
		dfs2(v,v);
	}
}
struct SegmentTree{
	#define ls p<<1
	#define rs p<<1|1
	#define lson p<<1,l,mid
	#define rson p<<1|1,mid+1,r
	int tr[400005],tag[400005];
	void pushUp(int p){tr[p]=tr[ls]+tr[rs];}
	void pushDown(int p,int l,int r)
	{
		if(tag[p])
		{
			int mid=(l+r)>>1;
			tr[ls]=(mid-l+1)-tr[ls];
			tr[rs]=(r-mid)-tr[rs];
			tag[ls]^=1; tag[rs]^=1;
			tag[p]^=1;
		}
	}
	void Build(int p,int l,int r)
	{
		if(l==r)
		{
			tr[p]=sizLeaf[To[l]];
			return;
		}
		int mid=(l+r)>>1;
		Build(lson); Build(rson);
		pushUp(p);
	}
	void Modify(int p,int l,int r,int lx,int rx)
	{
		if(lx<=l&&r<=rx)
		{
			tr[p]=(r-l+1)-tr[p];
			tag[p]^=1;
			return;
		}
		int mid=(l+r)>>1;pushDown(p,l,r);
		if(lx<=mid) Modify(lson,lx,rx);
		if(mid<rx)  Modify(rson,lx,rx);
		pushUp(p);
	}
	int Query(int p,int l,int r,int lx,int rx)
	{
		if(lx<=l&&r<=rx) return tr[p];
		int mid=(l+r)>>1,ret=0;pushDown(p,l,r);
		if(lx<=mid) ret+=Query(lson,lx,rx);
		if(mid<rx)  ret+=Query(rson,lx,rx);
		return ret;
	}
}Seg;
void ModifyPath(int x,int y)
{
//	printf("%d %d:",x,y);
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		Seg.Modify(1,1,n,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	Seg.Modify(1,1,n,dfn[x],dfn[y]);
//	for(int i=1;i<=n;i++) printf("%d ",Seg.Query(1,1,n,dfn[i],dfn[i]));puts("");
}
vector <int> Changed,V;
int main() {
//	freopen("1.in","r",stdin);
//	freopen("1.out","w",stdout);
	scanf("%d %d",&n,&q);
	for(int i=1,x,y;i<n;i++)
	{
		scanf("%d %d",&x,&y);
		G[x].push_back(y);
		G[y].push_back(x);
		deg[x]++;deg[y]++;
	}
	int Sum=0,Tmp;
	for(int i=1;i<=n;i++) if(deg[i]==1) IsLeaf[i]=true,Sum++; 
	dfs1(1,0);dfs2(1,1);
	Seg.Build(1,1,n);
//	for(int i=1;i<=n;i++) printf("%d ",Seg.Query(1,1,n,dfn[i],dfn[i]));puts("");
	Tmp=Sum;
	while(q--)
	{
		Sum=Tmp;
		scanf("%d",&m);
		for(int i=1,x;i<=m;i++)
		{
			scanf("%d",&x);
			if(IsLeaf[x])
			{
				Changed.push_back(x);
				IsLeaf[x]=false;
				continue;
			}
			V.push_back(x);Sum++;
			ModifyPath(x,1);
		}
		if(Sum&1) puts("-1");
		else printf("%d\n",((n+m)<<1)-2-(Seg.tr[1])-m);
		for(int i=0;i<V.size();i++) ModifyPath(V[i],1);
		for(int i=0;i<Changed.size();i++) IsLeaf[Changed[i]]=true;
		V.clear();Changed.clear();
	}
	return 0;
}

标签:100005,结点,int,题解,tr,叶子,CEOI2020,son,大扫除
来源: https://www.cnblogs.com/Azazel/p/15192326.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有