「AHOI2022」钥匙
想搞成一个好维护的形式,这个 \(5\) 把钥匙要用起来。
那首先考虑一点实现的问题,我们对同一种颜色建出虚树,然后以每个钥匙为根遍历一遍整棵树考虑造一点信息。
先看到 A 性质,猜测我们要通过一些特殊的匹配方式变成一条路径如果被包含则答案加一。
※ 那么考虑用栈储存钥匙,每次用栈顶解锁宝箱。然后栈底的钥匙(也就是当前的根)和与之匹配的宝箱形成一条合法路径(有方向)。
剩下的工作是个二维数点。虽然一眼看起来非常傻逼,但是思路比较巧妙阿。
/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double DB;
typedef unsigned long long ULL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read()
{
int x=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
return x;
}
void write(int x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
int fa[19][500005],siz[500005];
int lgs[500005],dep[500005];
int dfn[500005],sjc;
vector<int> G[500005];
vector<int> C[500005];
int n,q;
int t[500005],c[500005];
bool Ek[500005],Et[500005];
void dfs(int u,int f)
{
dfn[u]=++sjc;
dep[u]=dep[f]+1;
fa[0][u]=f;
siz[u]=1;
for(auto v:G[u]) if(v^f) dfs(v,u),siz[u]+=siz[v];
}
inline bool Inside(int u,int p){return dfn[u]<=dfn[p] && dfn[p]<dfn[u]+siz[u];}
inline int LCA(int u,int v)
{
if(dep[u]>dep[v]) swap(u,v);
while(dep[u]<dep[v]) v=fa[lgs[dep[v]-dep[u]]][v];
if(u==v) return u;
for(int i=18;~i;--i) if(fa[i][u]^fa[i][v]) u=fa[i][u],v=fa[i][v];
return fa[0][u];
}
vector<int> V[500005];
int seq[1000005];
inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
void build(int col)
{
static int cnt=0;
for(int i=1;i<=cnt;++i) V[seq[i]].clear();
cnt=0;
for(auto p:C[col]) seq[++cnt]=p;
sort(seq+1,seq+1+cnt,cmp);
for(int i=cnt;i>=2;--i) seq[++cnt]=LCA(seq[i],seq[i-1]);
sort(seq+1,seq+1+cnt,cmp);
cnt=unique(seq+1,seq+1+cnt)-seq-1;
for(int i=2,lca;i<=cnt;++i) V[lca=LCA(seq[i-1],seq[i])].push_back(seq[i]),V[seq[i]].push_back(lca);
}
inline int lowbit(int x){return x&(-x);}
struct BinaryIndexedTree{
int a[500005];
void modify(int x,int v){for(int i=x;i<=n;i+=lowbit(i)) a[i]+=v;}
void modify(int l,int r,int v){modify(l,v),modify(r+1,-v);}
int query(int x){int ans=0;for(int i=x;i;i^=lowbit(i)) ans+=a[i];return ans;}
}bit;
vector<pair<pair<int,int>,int>> S[500005];
#define mp make_pair
inline int kthAcc(int u,int k){for(int i=18;~i;--i) if((k>>i)&1) u=fa[i][u];return u;}
inline void Add(int u,int v)
{
// printf("%d %d\n",u,v);
if(Inside(u,v))
{
int p=kthAcc(v,dep[v]-dep[u]-1);
S[dfn[v]].push_back(mp(mp(1,dfn[p]-1),1));
S[dfn[v]].push_back(mp(mp(dfn[p]+siz[p],n),1));
S[dfn[v]+siz[v]].push_back(mp(mp(1,dfn[p]-1),-1));
S[dfn[v]+siz[v]].push_back(mp(mp(dfn[p]+siz[p],n),-1));
}
else if(Inside(v,u))
{
int p=kthAcc(u,dep[u]-dep[v]-1);
S[1].push_back(mp(mp(dfn[u],dfn[u]+siz[u]-1),1));
S[dfn[p]].push_back(mp(mp(dfn[u],dfn[u]+siz[u]-1),-1));
S[dfn[p]+siz[p]].push_back(mp(mp(dfn[u],dfn[u]+siz[u]-1),1));
}
else
{
S[dfn[v]].push_back(mp(mp(dfn[u],dfn[u]+siz[u]-1),1));
S[dfn[v]+siz[v]].push_back(mp(mp(dfn[u],dfn[u]+siz[u]-1),-1));
}
}
int F;
void Vdfs(int u,int f,int w=0)
{
if(w<0) return ;
// printf("%d %d %d %d\n",F,u,f,w);
for(auto v:V[u])
{
if(v==f) continue;
if(!w && c[v]==c[F] && t[v]==2)
{
// printf("%d: ",u),
Add(F,v);
continue;
}
int d=0;
if(c[v]==c[F])
{
if(t[v]==1) d=1;
else d=-1;
}
Vdfs(v,u,w+d);
}
}
vector<pair<int,int>> Q[500005];
int ans[1000005];
int main(){
// freopen("keys3.in","r",stdin);
// freopen("keys.out","w",stdout);
n=read(),q=read();
for(int i=1;i<=n;++i)
{
t[i]=read(),c[i]=read();
C[c[i]].push_back(i);
if(t[i]==1) Ek[c[i]]=true;
else Et[c[i]]=true;
}
for(int i=2;i<=n;++i) lgs[i]=lgs[i>>1]+1;
for(int i=1;i<n;++i)
{
int u=read(),v=read();
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
for(int i=1;i<=18;++i) for(int j=1;j<=n;++j) fa[i][j]=fa[i-1][fa[i-1][j]];
for(int i=1;i<=n;++i)
{
if(!Ek[i] || !Et[i]) continue;
build(i);
for(auto p:C[i])
{
if(t[p]==2) continue;
Vdfs(F=p,0);
}
// puts("");
}
for(int i=1;i<=q;++i)
{
int u=read(),v=read();
Q[dfn[v]].push_back(mp(dfn[u],i));
}
for(int i=1;i<=n;++i)
{
for(auto st:S[i]) bit.modify(st.first.first,st.first.second,st.second);
for(auto st:Q[i]) ans[st.second]=bit.query(st.first);
}
for(int i=1;i<=q;++i) write(ans[i]),puts("");
return 0;
}