2024.7.26模拟赛8

模拟赛

抽象比赛,含金量最高的是题目背景?

好像还是连续的。。。

T1 Same Integers

题目背景

签到题,因为只有加操作,目标是将两个较小的数加成最大的。

根据差的奇偶判断能否加二得到,如果不能先加一调一下。(简单题,题解抽象一点也没事吧)

code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5+5;
LL a[3],ans;
int main()
{
	for(int i=0;i<3;i++) scanf("%lld",&a[i]);
	sort(a,a+3);
	int x=a[2]-a[0],y=a[2]-a[1];
	if((x&1) && (y&1)) ans=(x-1>>1)+(y-1>>1)+1;
	else if(x&1) ans=(y>>1)+(x+1>>1)+1;
	else if(y&1) ans=(x>>1)+(y+1>>1)+1;
	else ans=(x>>1)+(y>>1);
	printf("%lld\n",ans);
	return 0;
}

T2 Qpwoeirut and Vertices

题目背景

首先要想到建立最小生成树,因为我们只在乎使某个连通块第一次被连通的边,后面再加边都可以忽略,所以最终建出的一定是一棵树。

然后考虑答案是什么,将边的编号赋成边权,那么使 \(u,v\) 连通的边权最大的边就是答案,也就是路径最大值。

使 \([l,r]\) 连通也很简单,就是使每两个相邻的节点连通,然后取区间最大值。

路径最大值可以用树剖 + ST 表,区间最值也用 \(ST\) 维护就好,发现是数据结构裸题。

正解是新科技:克鲁斯卡尔重构树

不同于最小生成树,克鲁斯卡尔重构树是对于每一条边建一个虚点,点权等于原边权,虚点向原边的两个端点所在连通块的代表点连边。

因为加边按顺序,所以这样重构的树(森林)从根到叶子的权值一定是单调不上升的,那么使两点连通的最小权值就是重构树离他们最近的祖先的点权

LCA + ST 表即可。

code(ST + ST)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int t;
int n,m,q;
struct K {int u,v,w;} k[N<<1];
inline bool cmp(const K &x,const K &y) {return x.w<y.w;}
int head[N],tot;
struct E {int u,v,w;} e[N<<1];
inline void add(int u,int v,int w) {e[++tot]={head[u],v,w}; head[u]=tot;}
struct BCJ
{
	int fa[N];
	inline void init() {for(int i=1;i<=n;i++) fa[i]=i;}
	inline int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}	
} bcj;

int dfn[N],dep[N],son[N],sz[N],cnt,rk[N],fa[N],top[N],a[N];

void dfs1(int u,int f)
{
	dep[u]=dep[f]+1; son[u]=-1; sz[u]=1; fa[u]=f;
	for(int i=head[u];i;i=e[i].u)
	{
		int v=e[i].v;
		if(v==f) continue;
		a[v]=e[i].w;
		dfs1(v,u);
		sz[u]+=sz[v];
		if(son[u]==-1||sz[son[u]]<sz[v]) son[u]=v;
	}
}
void dfs2(int u,int t)
{
	top[u]=t; dfn[u]=++cnt; rk[cnt]=u;
	if(son[u]==-1) return;
	dfs2(son[u],t);
	for(int i=head[u];i;i=e[i].u)
	{
		int v=e[i].v;
		if(v!=son[u]&&v!=fa[u]) dfs2(v,v);
	}
}
struct ST1
{
	int st[30][N];
	inline void bui()
	{
		for(int i=1;i<=n;i++) st[0][i]=a[rk[i]];
		for(int i=1;i<=25;i++) 
			for(int j=1;j+(1<<i)-1<=n;j++)
				st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
	}
	inline int que(int l,int r)
	{
		int k=__lg(r-l+1);
		return max(st[k][l],st[k][r-(1<<k)+1]);
	}
} st;
int Que(int x,int y)
{
	int res=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		res=max(res,st.que(dfn[top[x]],dfn[x]));
		x=fa[top[x]];
	}
	if(x==y) return res;
	if(dep[x]>dep[y]) swap(x,y);
	res=max(res,st.que(dfn[x]+1,dfn[y]));
	return res;
}
struct ST2
{
	int st[30][N];
	inline void bui()
	{
		for(int i=1;i<n;i++) st[0][i]=Que(i,i+1);
		for(int i=1;i<=25;i++) 
			for(int j=1;j+(1<<i)-1<n;j++)
				st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
	}
	inline int que(int l,int r)
	{
		int k=__lg(r-l+1);
		return max(st[k][l],st[k][r-(1<<k)+1]);
	}
} st2;
void init()
{
	cnt=0; tot=0;
	memset(head,0,sizeof(head));
}
int main()
{
//	freopen("lagrange3.in","r",stdin);
//	freopen("o1.out","w",stdout);
	scanf("%d",&t);
	while(t--) 
	{
		init();
		scanf("%d%d%d",&n,&m,&q);  bcj.init();
		for(int i=1;i<=m;i++)
		{
			int x,y; scanf("%d%d",&x,&y);
			k[i]={x,y,i};
		}
		for(int i=1;i<=m;i++)
		{
			int fx=bcj.find(k[i].u),fy=bcj.find(k[i].v);
			if(fx!=fy) bcj.fa[fx]=fy,add(k[i].u,k[i].v,k[i].w),add(k[i].v,k[i].u,k[i].w);
		}
		dfs1(1,0); dfs2(1,1);
		st.bui(); st2.bui();
		while(q--)
		{
			int x,y; scanf("%d%d",&x,&y);
			if(x==y) printf("0\n");
			else printf("%d\n",st2.que(x,y-1));
		}	
	}
	return 0;
}
code(重构树)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
int t,q,n,m;
struct K {int u,v;} k[N];
int head[N],tot,num,w[N],fa[30][N],dep[N],a[N];
struct E {int u,v;} e[N<<1];
inline void add(int u,int v) {e[++tot]={head[u],v}; head[u]=tot;}
struct BCJ
{
	int fa[N];
	void bui()
	{
		for(int i=1;i<=(n<<1);i++) fa[i]=i;
	}
	inline int find(int x)
	{
		if(x!=fa[x]) fa[x]=find(fa[x]);
		return fa[x];
	}
} bcj;
void dfs(int u,int f)
{
	dep[u]=dep[f]+1; fa[0][u]=f;
	for(int i=1;i<=20;i++) fa[i][u]=fa[i-1][fa[i-1][u]];
	for(int i=head[u];i;i=e[i].u)
	{
		int v=e[i].v; if(v==f) continue;
		dfs(v,u);
	}
}
int lca(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=20;i>=0;i--) if(dep[fa[i][x]]>=dep[y]) x=fa[i][x];
	if(x==y) return x;
	for(int i=20;i>=0;i--) if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y];
	return fa[0][x];
}
struct ST
{
	int st[20][N];
	void bui()
	{
		for(int i=1;i<n;i++) st[0][i]=a[i];
		for(int i=1;i<=20;i++)
			for(int j=1;j<n;j++)
				st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
	}
	int que(int l,int r)
	{
		int k=__lg(r-l+1);
		return max(st[k][l],st[k][r-(1<<k)+1]);
	}
} st;
int main()
{
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d",&n,&m,&q); tot=0,num=n;
		for(int i=1;i<=m;i++) scanf("%d%d",&k[i].u,&k[i].v);
		for(int i=1;i<=n<<1;i++)
		{
			bcj.fa[i]=i; head[i]=0; dep[i]=0;
		}
		for(int i=1;i<=m;i++)
		{
			int fx=bcj.find(k[i].u),fy=bcj.find(k[i].v);
			if(fx==fy) continue;
			bcj.fa[fx]=bcj.fa[fy]=++num; w[num]=i;
			add(num,fx); add(num,fy);
		}
		for(int i=num;i>=n+1;i--)
			if(!dep[i]) dfs(i,0);
		for(int i=1;i<n;i++)
		{
			int d=lca(i,i+1);
			a[i]=w[d];
		}
		st.bui();
		while(q--)
		{
			int l,r; scanf("%d%d",&l,&r);
			if(l==r) printf("%d ",0);
			else printf("%d ",st.que(l,r-1));
		}
		printf("\n");
	}
	return 0;
}

T3 Subset Sum Game

咕咕咕。。。

posted @ 2024-07-30 12:16  ppllxx_9G  阅读(16)  评论(1编辑  收藏  举报