2019/10/26 校内模拟

T1 走格子

这算是一道结论题吧,考场上写了个 d f s dfs dfs 发现 n n n 的答案就是 n n n

std 的推导如下:
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
	scanf("%d",&n);
	printf("%d\n",n%998244353);
	return 0;
}
T2 换公路

这道题在考场上想了大部分的 s t d std std,但是没有调出来,有点可惜。

考虑第一棵树的边 e 1 e_1 e1 和第二棵树的边 e 2 e_2 e2 在满足什么条件时可以互换,即:

  • e 2 e_2 e2 e 1 e_1 e1 加进第二棵树时形成的环上。
  • e 1 e_1 e1 e 2 e_2 e2 加进第一棵树时形成的环上。

现在就是要对于每个 e 1 e_1 e1,询问能与之互换的 e 2 e_2 e2 数量。

那么我们把 e 2 e_2 e2 在第一棵树上差分一下,相当于是处理第 1 1 1 个限制。然后在第一棵树上 d f s dfs dfs 求答案。对于每一条 e 1 e_1 e1,把能 “ “ 覆盖 ” ” 它的 e 2 e_2 e2 的权值赋成 1 1 1(差分的时候即可完成),然后在第 2 2 2 棵树上查 e 1 e_1 e1 两端点的链的权值,相当于是处理第 2 2 2 个限制

这样做的话我们要支持单点加链查询,如果树剖暴力跳重链的话 O ( n log ⁡ 2 n ) O(n\log^2n) O(nlog2n) 过不了。

有一个小优化,我们可以维护子树加单点查询,就有点像树状数组的思想一样。由于子树的 d f s dfs dfs 序是连续的,不需要暴力跳重链来修改,时间复杂度就降为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

然后这个东西可以不用线段树,用树状数组就可以了。

#include<bits/stdc++.h>
using namespace std;
namespace IO{
	const int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>
	inline T Read(){
		char c;T x;
		while(!isdigit(c=gc()));x=c^48;
		while( isdigit(c=gc())) x=(x+(x<<2)<<1)+(c^48);
		return x;
	}
	inline int in()  {return Read<int>();}
}
using IO::in;
const int N=1e6+5;
int n,ans[N];
struct edge{int u,v;}e1[N],e2[N];
struct edges{
	int t,first[N],v[N<<1],nxt[N<<1];
	void add(int x,int y)  {nxt[++t]=first[x],first[x]=t,v[t]=y;}
	int tot,id[N],dep[N],fa[N],Size[N],son[N],top[N],pos[N];
	void dfs1(int x){
		Size[x]=1;
		for(int i=first[x];i;i=nxt[i]){
			int to=v[i];
			if(to==fa[x])  continue;
			fa[to]=x,dep[to]=dep[x]+1,id[to]=(i+1)/2;
			dfs1(to),Size[x]+=Size[to];
			if(Size[to]>Size[son[x]])  son[x]=to;
		}
	}
	void dfs2(int x,int tp){
		top[x]=tp,pos[x]=++tot;
		if(son[x])  dfs2(son[x],tp);
		for(int i=first[x];i;i=nxt[i])
			if(v[i]!=fa[x]&&v[i]!=son[x])  dfs2(v[i],v[i]);
	}
	int LCA(int x,int y){
		while(top[x]!=top[y]){
			if(dep[top[x]]<dep[top[y]])  swap(x,y);
			x=fa[top[x]];
		}
		return (dep[x]<dep[y])?x:y;
	}
}T1,T2;
typedef pair<int,int> pii;
vector<pii> p[N];
namespace BIT{
	int bit[N];
	#define lowbit(x) (x&(-x))
	void add(int x,int val)  {for(;x<=n;x+=lowbit(x))bit[x]+=val;}
	int Query(int x,int ans=0)  {for(;x;x-=lowbit(x))ans+=bit[x];return ans;}
	void update(int l,int r,int val)  {add(l,val),add(r+1,-val);}
	int ask(int x,int y)  {return Query(T2.pos[x])+Query(T2.pos[y])-2*Query(T2.pos[T2.LCA(x,y)]);}
	#undef lowbit
}
void dfs(int x,int fa){
	int pre=0;
	if(x>1)  pre=BIT::ask(x,fa);
	for(int i=T1.first[x];i;i=T1.nxt[i]){
		int to=T1.v[i];
		if(to==fa)  continue;
		dfs(to,x);
	}
	for(int i=0;i<p[x].size();++i){
		int now=p[x][i].first,val=p[x][i].second;
		BIT::update(T2.pos[now],T2.pos[now]+T2.Size[now]-1,val);
	}
	ans[T1.id[x]]=BIT::ask(x,fa)-pre;
}
int main(){
	n=in();
	for(int i=1,x,y;i<n;++i)  x=in(),y=in(),T1.add(x,y),T1.add(y,x),e1[i]=(edge){x,y};
	for(int i=1,x,y;i<n;++i)  x=in(),y=in(),T2.add(x,y),T2.add(y,x),e2[i]=(edge){x,y};
	T1.dfs1(1),T1.dfs2(1,1),T2.dfs1(1),T2.dfs2(1,1);
	for(int i=1;i<n;++i){
		int u=e2[i].u,v=e2[i].v;
		if(T2.dep[u]>T2.dep[v])  swap(u,v);
		p[u].push_back(pii(v,1));
		p[v].push_back(pii(v,1));
		p[T1.LCA(u,v)].push_back(pii(v,-2));
	}
	dfs(1,0);
	for(int i=1;i<n;++i)  printf("%d ",ans[i]);
	return 0;
}
T3 找宝藏

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
namespace IO{
	const int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>
	inline T Read(){
		char c;T x;
		while(!isdigit(c=gc()));x=c^48;
		while( isdigit(c=gc())) x=(x+(x<<2)<<1)+(c^48);
		return x;
	}
	inline int in()  {return Read<int>();}
}
using IO::in;
const int N=2e5+5;
int n,m,q,rt;
int t[N][21],s[N][21],deg[N],son[N],f[N];
vector<int>e[N],val[N];
const int lim=1e9+5;
int add(int x,int y)  {return min(lim,x+y);}
void dfs(int x){
	if(f[x])  return;
	int heaviest=0;
	for(int &to:e[x]){
		dfs(to);
		if(f[to]>f[son[x]])  son[x]=to,heaviest=f[x]+1;
		f[x]=add(f[x],f[to]+1),val[x].push_back(f[x]);
	}
	t[x][0]=son[x],s[x][0]=heaviest;
	for(int i=1;i<=20;++i)  t[x][i]=t[t[x][i-1]][i-1],s[x][i]=add(s[x][i-1],s[t[x][i-1]][i-1]);
}
int find(int x,int k){
	if(!k)  return x;
	for(int i=20;~i;--i)
		if(t[x][i]&&s[x][i]<=k&&s[x][i]+f[t[x][i]]>=k)  return find(t[x][i],k-s[x][i]);
	int pos=lower_bound(val[x].begin(),val[x].end(),k)-val[x].begin();
	return pos?find(e[x][pos],k-val[x][pos-1]-1):find(e[x][0],k-1);
}
int main(){
	n=in(),m=in();
	for(int i=1,x,y;i<=m;++i){
		x=in(),y=in(),e[x].push_back(y),deg[y]++;
	}
	for(int i=1;i<=n;++i)  if(!deg[i])  rt=i;
	dfs(rt);q=in();
	while(q--){
		int S=in(),k=in();
		if(k>f[S])  {puts("-1");continue;}
		printf("%d\n",find(S,k));
	}
	return 0;
}

反思

关于这套题我的遗憾就是 T2。一是想到了 s t d std std 却没调出来,另一个就是暴力也没拿分。

由于要调正解就这样写的:

/*if(n<=3000)  subtask1::solve();
else  */subtask2::solve();

最后很慌就没有把注释删掉,然后正解又没有调出来。。。

这种 s b sb sb 错误在正式考试的时候一定不能再犯。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值