ICode9

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

题解-AHOI2022 钥匙

2022-05-20 19:03:35  阅读:125  来源: 互联网

标签:ch int 题解 top lca dep maxn AHOI2022 钥匙


通过这道题发现我是春春的滴嫩儿。

前两题一共花了我4.5h,也就是说我要去AH的话切完前两题比赛就结束了后面的题看都没得看。

还是要加强码力和熟练度啊。


首先考虑对每种颜色分别求解,那么我们可以把钥匙和宝箱看成一个括号匹配(怎么又是它),考虑在匹配的位置记入答案。那么可以枚举一对 \((1,2)\),看是否是一组匹配。然后计入答案就比较简单了,就是一个矩阵加,离线扫描线+树状数组即可。考虑如何判断?我们先把同一个颜色的数拿出来建虚树,然后考虑在虚树上往上跳,如果跳到某个位置不能匹配了就停止。容易发现跳的次数是常数(或者说是钥匙和宝箱个数的较小值)。于是这道题就做完了。

写代码的时候注意卡常。

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn=5e5+5;
template<typename T>
void read(T &x){
	T sgn=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar())if(ch=='-')sgn=-1;
	for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
	x*=sgn;
}
int n,m,op[maxn],col[maxn],dfn[maxn],pos[maxn],num,dep[maxn],f[maxn][21],sz[maxn];
int node[maxn],cnt,stk[maxn],top,bit[maxn];
vector<int>vec[maxn],zz[2][maxn],G[maxn];
vector<pair<int,int>>qq[maxn];
int ans[maxn<<1],pre[maxn];
struct Rec{
	int x,l,r,w;
	friend bool operator<(Rec a, Rec b){
		return a.x<b.x;
	}
}q[maxn*2*5];
int oo;
void ins(int x,int w){
	while(x<=n){
		bit[x]+=w;
		x+=x&-x;
	}
}
int qry(int x){
	int ret=0;
	while(x){
		ret+=bit[x];
		x-=x&-x;
	}
	return ret;
}
int eul[maxn<<1][21],jj,lg[maxn<<1],fir[maxn];
void dfs1(int u){
	dfn[pos[u]=++num]=u;
	sz[u]=1;
	for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
	eul[fir[u]=++jj][0]=u;
	for(int v:vec[u])if(v!=f[u][0]){
		dep[v]=dep[u]+1;
		f[v][0]=u;
		dfs1(v);
		eul[++jj][0]=u;
		sz[u]+=sz[v];
	}
}
int Min(int a,int b){
	if(dep[a]<dep[b])return a;
	return b;
}
void init(){
	for(int j=1;j<=20;j++){
		for(int i=1;i+(1<<j)<=jj;i++){
			eul[i][j]=Min(eul[i][j-1],eul[i+(1<<(j-1))][j-1]);
		}
	}
	lg[0]=-1;
	for(int i=1;i<=jj;i++)lg[i]=lg[i>>1]+1;
}
int jump(int u,int d){
	for(int i=0;i<=20&&d;i++)if(d&(1<<i))u=f[u][i],d-=1<<i;
	return u;
}
int LCA(int u,int v){
	u=fir[u];v=fir[v];
	if(u>v)swap(u,v);
	int k=lg[v-u+1];
	return Min(eul[u][k],eul[v-(1<<k)+1][k]);
}
bool cmp(int a,int b){
	return pos[a]<pos[b];
}
void add_edge(int u,int v){
	G[u].pb(v);
}
void ins(int u){
	if(top==0)return stk[top=1]=u,void();
	int lca=LCA(u,stk[top]);
	while(top>1&&dep[stk[top-1]]>dep[lca])add_edge(stk[top-1],stk[top]),top--;
	if(dep[lca]<dep[stk[top]])add_edge(lca,stk[top]),top--;
	if(!top||stk[top]!=lca)stk[++top]=lca;
	stk[++top]=u;
}
void build_virtual_tree(){
	sort(node+1,node+1+cnt,cmp);
	if(node[1]!=1)stk[top=1]=1;
	else top=0;
	for(int i=1;i<=cnt;i++)ins(node[i]);
	while(top>1)add_edge(stk[top-1],stk[top]),top--;
}
void dfs3(int u,int Fa,int cc){
	for(int v:G[u])if(v!=Fa){
		pre[v]=pre[u];
		if(col[u]==cc)pre[v]=u;
		dfs3(v,u,cc);
	}G[u].clear();
}
bool check(int u,int v,int cc){
	int lca=LCA(u,v);
	int sum=1;
	assert(col[u]==cc&&col[v]==cc);
	do{
		u=pre[u];
		if(dep[u]<dep[lca])break;
		if(op[u]==1)sum++;
		else sum--;
		if(u==lca){
			break;
		}
		if(sum<=0)return false;
	}while(dep[u]>dep[lca]);
	if(lca==v){
		return sum==0;
	}
	int ssum=-1;
	while(dep[v]>dep[lca]){
		v=pre[v];
		if(dep[v]<=dep[lca])break;
		if(op[v]==1)ssum++;
		else ssum--;
		if(ssum>=0)return false;
		if(ssum<-5)return false;
	}
	return sum+ssum==0;
}
int main(){
	read(n);read(m);
	for(int i=1;i<=n;i++){
		read(op[i]);read(col[i]);
		zz[op[i]-1][col[i]].pb(i);
	}
	for(int i=1,u,v;i<n;i++){
		read(u);read(v);
		vec[u].pb(v);
		vec[v].pb(u);
	}
	dep[1]=1;dfs1(1);init();
	for(int i=1;i<=n;i++)if(zz[0][i].size()&&zz[1][i].size()){
		cnt=0;
		for(int j:zz[0][i])node[++cnt]=j;
		for(int j:zz[1][i])node[++cnt]=j;
		build_virtual_tree();
		dfs3(1,0,i);
		for(int k:zz[1][i])for(int j:zz[0][i]){
			if(!check(j,k,i))continue;
			int lca=LCA(j,k);
			if(lca==j){
				int l=jump(k,dep[k]-dep[j]-1);
				q[++oo]=Rec{1,pos[k],pos[k]+sz[k]-1,1};
				q[++oo]=Rec{pos[l],pos[k],pos[k]+sz[k]-1,-1};
				q[++oo]=Rec{pos[l]+sz[l],pos[k],pos[k]+sz[k]-1,1};
			}else if(lca==k){
				int l=jump(j,dep[j]-dep[k]-1);
				q[++oo]=Rec{pos[j],1,pos[l]-1,1};
				q[++oo]=Rec{pos[j],pos[l]+sz[l],n,1};
				q[++oo]=Rec{pos[j]+sz[j],1,pos[l]-1,-1};
				q[++oo]=Rec{pos[j]+sz[j],pos[l]+sz[l],n,-1};	
			}else{
				q[++oo]=Rec{pos[j],pos[k],pos[k]+sz[k]-1,1};
				q[++oo]=Rec{pos[j]+sz[j],pos[k],pos[k]+sz[k]-1,-1};	
			}
		}
	}
	for(int i=1;i<=m;i++){
		int s,t;
		read(s);read(t);
		qq[pos[s]].pb(make_pair(pos[t],i));
	}
	sort(q+1,q+1+oo);
	for(int i=1,j=1;i<=n;i++){
		while(j<=oo&&q[j].x<=i){
			if(q[j].l>q[j].r){
				j++;
				continue;
			}
			ins(q[j].l,q[j].w);
			ins(q[j].r+1,-q[j].w);
			j++;
		}
		for(int k=0;k<(int)qq[i].size();k++){
			ans[qq[i][k].second]=qry(qq[i][k].first);
		}
	}
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
	return 0;
}

标签:ch,int,题解,top,lca,dep,maxn,AHOI2022,钥匙
来源: https://www.cnblogs.com/zcr-blog/p/16293444.html

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

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

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

ICode9版权所有