P8339 [AHOI2022] 钥匙 思考--zhengjun

发布时间 2023-07-12 21:24:54作者: A_zjzj

很容易考虑到计算贡献。

该问题的关键在于——如何使得钥匙和宝箱的对应关系不算重

Warning:有这样的二元对应关系,可以考虑一下转化为括号序列!

转化为括号序列之后,发现路径上括号串的对应关系能够预处理出来。

套个虚树和扫描线,就做完了。

代码

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=5e5+10,M=1e6+10;
int n,m,a[N],b[N];
vector<int>A[N];
int dft,bg[N],ed[N],dep[N],fa[N];
namespace QTree{
	int dft,pos[N],top[N],son[N],siz[N];
	void dfs1(int u){
		dep[u]=dep[fa[u]]+1,siz[u]=1;
		for(int v:A[u])if(v^fa[u]){
			fa[v]=u,dfs1(v);
			siz[u]+=siz[v];
			if(siz[v]>siz[son[u]])son[u]=v;
		}
	}
	void dfs2(int u,int t){
		top[u]=t,pos[bg[u]=++dft]=u;
		if(son[u])dfs2(son[u],t);
		for(int v:A[u])if(v^fa[u]&&v^son[u])dfs2(v,v);
		ed[u]=dft;
	}
	void init(){
		dfs1(1),dfs2(1,1);
	}
	int LCA(int u,int v){
		for(;top[u]^top[v];u=fa[top[u]]){
			if(dep[top[u]]<dep[top[v]])swap(u,v);
		}
		return dep[u]<dep[v]?u:v;
	}
	int kth(int u,int k){
		for(;dep[u]-dep[top[u]]<k;u=fa[top[u]])k-=dep[u]-dep[top[u]]+1;
		return pos[bg[u]-k];
	}
}
using QTree::LCA;
using QTree::kth;
vector<int>pos[N],B[N];
int top,stk[N];
void add(int u,int v){
	B[u].push_back(v),B[v].push_back(u);
}
int tag[N];
bool isin(int u,int t){
	return bg[t]<=bg[u]&&bg[u]<=ed[t];
}
struct opts{
	int l,r,x;
};
vector<opts>o[N];
void update(int x,int y,int l,int r){
	if(x>y||l>r)return;
	o[x].push_back({l,r,1}),o[y+1].push_back({l,r,-1});
}
void insert(int u,int v){
//	fprintf(stderr,"%d %d\n",u,v);
	if(isin(u,v)){
		int x=kth(u,dep[u]-dep[v]-1);
		update(bg[u],ed[u],1,bg[x]-1);
		update(bg[u],ed[u],ed[x]+1,n);
	}
	else if(isin(v,u)){
		int x=kth(v,dep[v]-dep[u]-1);
		update(1,bg[x]-1,bg[v],ed[v]);
		update(ed[x]+1,n,bg[v],ed[v]);
	}
	else{
		update(bg[u],ed[u],bg[v],ed[v]);
	}
}
void ins(int s,int u,int fa=0,int now=0){
	now+=tag[u];
	if(!now)return insert(s,u);
	for(int v:B[u])if(v^fa)ins(s,v,u,now);
}
void clr(int u,int fa=0){
	for(int v:B[u])if(v^fa)clr(v,u);
	B[u].clear();
}
void solve(vector<int>&p){
	if(p.empty())return;
	sort(p.begin(),p.end(),[](int x,int y){return bg[x]<bg[y];});
	stk[top=1]=p[0];
	for(int len=p.size(),i=1;i<len;i++){
		int x=LCA(stk[top],p[i]);
		for(;top>1&&dep[stk[top-1]]>=dep[x];top--)add(stk[top-1],stk[top]);
		if(stk[top]^x)add(x,stk[top--]);
		if(stk[top]^x)stk[++top]=x;
		if(stk[top]^p[i])stk[++top]=p[i];
	}
	for(int i=1;i<top;i++)add(stk[i],stk[i+1]);
	for(int u:p)tag[u]=3-a[u]*2;
	for(int u:p)if(tag[u]>0)ins(u,u);
	clr(stk[1]);
	for(int u:p)tag[u]=0;
}
namespace BIT{
	int c[N];
	void add(int x,int y){
		for(;x<=n;x+=x&-x)c[x]+=y;
	}
	void get(int x,int &y){
		for(y=0;x;x^=x&-x)y+=c[x];
	}
}
vector<pair<int,int> >q[N];
int ans[M];
int main(){
	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);
	for(int i=1,u,v;i<n;i++){
		scanf("%d%d",&u,&v);
		A[u].push_back(v),A[v].push_back(u);
	}
	QTree::init();
	for(int i=1;i<=n;i++)pos[b[i]].push_back(i);
	for(int i=1;i<=n;i++)solve(pos[i]);
	for(int i=1,u,v;i<=m;i++){
		scanf("%d%d",&u,&v);
		q[bg[u]].push_back({bg[v],i});
	}
	for(int i=1;i<=n;i++){
		for(opts x:o[i])BIT::add(x.l,x.x),BIT::add(x.r+1,-x.x);
		for(auto x:q[i])BIT::get(x.first,ans[x.second]);
	}
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
	return 0;
}