P8339 [AHOI2022] 钥匙

大神 P2441M 💩🍽️。🤯🤯🤯

考虑这个询问,因为是固定的策略,所以每个钥匙 \(u\) 实际上只会跟路径上后一个同种类的箱子 \(v\) 匹配,并且只要路径包含 \(u,v\),且方向与 \(u\to v\) 同向就一定被统计。

预处理所有的钥匙、箱子对 \((u,v)\),每次从钥匙搜,若第一次满足 \(cnt_{box}=cnt_{key}\) 则所在点 \(v\) 能与钥匙 \(u\) 匹配。

考虑满足条件的路径 \(x\to y\) 限制。

· \(\operatorname{lca}(u,v)\notin \{u,v\}\) 则限制为 \(x\in sub_u\wedge y\in sub_v\)\(sub\) 是子树集合。

· \(\operatorname{lca}(u,v)=u\) 限制为 \(x\notin sub_w,y\in sub_v(w\in son_u,\mathrm{lca}(w,v)=w)\)

· \(\operatorname{lca}(u,v)=v\) 限制为 \(x\in sub_u,y\notin sub_w(w\in son_v,\mathrm{lca}(w,u)=w)\)

按 dfs 序容易转化为矩阵加单点查询,扫描线即可。

问题在如何求出所有钥匙、箱子对 \((u,v)\)。有性质每种颜色的钥匙数量 \(\le 5\)。但颜色数一大就炸了,考虑实际上有用的节点只有与钥匙同色的点,显然建出该颜色的虚树,则所有虚树总点数是 \(O(n)\) 的,预处理的复杂度也降至 \(O(n)\)

Takanashi Rikka
#include<bits/stdc++.h>
using namespace std;
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);o
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define il inline
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define ve vector
#define intz(x,y) memset((x),(y),sizeof((x)))
template<typename Type>il void cmx(Type &x,Type y){if(y>x)x=y;}
template<typename Type>il void cmn(Type &x,Type y){if(y<x)x=y;}
template<typename Type>
il typename Type::value_type MAX(Type f) {
    auto res=*f.begin();
	for(auto i=f.begin();i!=f.end();cmx(res,*i),i++);
	return res;
}
template<typename Type>
il typename Type::value_type MIN(Type f) {
    auto res=*f.begin();
	for(auto i=f.begin();i!=f.end();cmn(res,*i),i++);
	return res;
}
#define lowbit(x) (x&-x)
#define pcount(x) __builtin_popcountll(x)
const int N=1e6+5;
ve<int>p[N],ky[N],e[N],E[N];
int id[N],tot,dfn[N],ct,lb[N],F[N],d[N],z[N],tp,siz[N],C[N],fl[N];
void dfs(int u,int fa){
	dfn[u]=++ct,siz[u]=1;
	d[u]=d[F[u]=fa]+1;
	int x=lb[fa],y=lb[x];
	lb[u]=(d[fa]-d[x]==d[x]-d[y]?y:fa);
	for(int v:e[u])if(v^fa)
		dfs(v,u),siz[u]+=siz[v];
}
il int lca(int x,int y){
	if(d[x]<d[y])swap(x,y);
	while(d[x]>d[y])x=(d[lb[x]]>=d[y]?lb[x]:F[x]);
	while(x^y)(lb[x]^lb[y]?(x=lb[x],y=lb[y]):(x=F[x],y=F[y]));
	return x;
}
il void add(int u,int v){E[u].pb(v),E[v].pb(u);}
ve<pii>opt;
void Dfs(int u,int fa,int c,int tv){
	// cerr<<"*"<<u<<' '<<c<<'\n';
	if(!c)return opt.pb(mp(tv,u)),void();
	for(int v:E[u])if(v^fa){
		int res=c;
		if(C[v]==C[tv])
			res+=(fl[v]?1:-1);
		Dfs(v,u,res,tv);
	}
}
il int jp(int x,int y){
	if(d[x]<d[y])swap(x,y);
	while(d[x]>d[y]+1)x=(d[lb[x]]>=d[y]+1?lb[x]:F[x]);
	return x;
}
struct optr{int l,r,x;};
ve<optr>q[N],qry[N];
int t[N],n,m,ans[N];
il void upd(int x,int d){for(;x<=n;x+=lowbit(x))t[x]+=d;}
il int ask(int x){int res=0;for(;x;x-=lowbit(x))res+=t[x];return res;}
il void update(int l,int r,int x){upd(l,x),upd(r+1,-x);}
void UesugiErii(){
	cin>>n>>m;
	for(int i=1,c;i<=n;i++){
		cin>>fl[i]>>c,--fl[i],C[i]=c;
		if(!fl[i])ky[c].pb(i);
		else p[c].pb(i);
	}
	for(int i=1,u,v;i<n;i++)
		cin>>u>>v,e[u].pb(v),e[v].pb(u);
	dfs(1,0);
	for(int col=1;col<=n;col++){
		ve<int>q;tot=0;
		for(int j:p[col])id[++tot]=j;
		for(int j:ky[col])id[++tot]=j;
		sort(id+1,id+1+tot,[&](int x,int y){return dfn[x]<dfn[y];});
		z[tp=1]=1,E[1].clear(),q.pb(1);
		for(int i=1;i<=tot;i++){
			if(id[i]==1)continue;
			int lc=lca(z[tp],id[i]);
			if(lc!=z[tp]){
				while(dfn[z[tp-1]]>dfn[lc])
					add(z[tp-1],z[tp]),--tp;
				if(lc!=z[tp-1])
					 E[lc].clear(),add(lc,z[tp]),z[tp]=lc,q.pb(lc);
				else add(lc,z[tp]),--tp;
			}
			E[id[i]].clear();
			z[++tp]=id[i];q.pb(id[i]);
		}
		for(int i=1;i<tp;i++)add(z[i],z[i+1]);
		for(int i:ky[col])Dfs(i,0,(fl[i]?1:-1),i);
	}
	// for(pii x:opt)cerr<<x.fi<<' '<<x.se<<'\n';
	for(pii x:opt){
		int lc=lca(x.fi,x.se);
		if(lc!=x.fi&&lc!=x.se)
			q[dfn[x.fi]].pb({dfn[x.se],dfn[x.se]+siz[x.se]-1,1}),
			q[dfn[x.fi]+siz[x.fi]].pb({dfn[x.se],dfn[x.se]+siz[x.se]-1,-1});
		else if(lc==x.fi){
			q[1].pb({dfn[x.se],dfn[x.se]+siz[x.se]-1,1});
			int v=jp(x.se,x.fi);
			q[dfn[v]].pb({dfn[x.se],dfn[x.se]+siz[x.se]-1,-1}),
			q[dfn[v]+siz[v]].pb({dfn[x.se],dfn[x.se]+siz[x.se]-1,1});
		}else{
			q[dfn[x.fi]].pb({1,n,1});
			q[dfn[x.fi]+siz[x.fi]].pb({1,n,-1});
			int v=jp(x.se,x.fi);
			q[dfn[x.fi]].pb({dfn[v],dfn[v]+siz[v]-1,-1}),
			q[dfn[x.fi]+siz[x.fi]].pb({dfn[v],dfn[v]+siz[v]-1,1});
		}
	}
	for(int i=1,s,t;i<=m;i++)
		cin>>s>>t,qry[dfn[s]].pb({dfn[t],i});
	for(int i=1;i<=n;i++){
		for(optr x:q[i])update(x.l,x.r,x.x);
		for(optr x:qry[i])ans[x.r]=ask(x.l);
	}
	for(int i=1;i<=m;i++)
		cout<<ans[i]<<'\n';
}
signed main(){
	//IO();
	cfast;
	int _=1;//cin>>_;
	for(;_;_--)UesugiErii();
	return 0;
}
posted @ 2026-01-23 12:56  Uesugi1  阅读(0)  评论(0)    收藏  举报