RT,思路就是求一个 dfn 序然后 cdq 三维偏序。
#include <bits/stdc++.h>
#define ll long long
#define _cst const
#define _IfD long long
#define _siz 20
using namespace std;
char buf[1<<_siz],buffer[1<<_siz],*p1=buf,*p2=buf,c='\n';
int op1=-1; _cst int op2=(1<<_siz)-1;
inline char gc(){return (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<_siz,stdin)),p1==p2?EOF:*p1++);}
inline void flush(){fwrite(buffer,1,op1+1,stdout),op1=-1;}
inline void pc(_cst char &x){if(op1==op2)flush();buffer[++op1]=x;}
template<typename T>void read(T &w){
w=0;bool f=1;char ch=gc();
for(;!isdigit(ch);ch=gc()) if(ch=='-')f=0;
for(;'0'<=ch && ch<='9';ch=gc()) w=(w<<1)+(w<<3)+(ch^48);
w=f?w:-w;
}template<typename T,typename ...Arg>void read(T &w,Arg &...arg){
read(w); read(arg...);
}template<typename T>void wrt(T x){
if(x<0) pc('-'),x=-x;
if(x>9) wrt(x/10);
pc(x%10|48);
}template<typename T>void write(T x){
wrt(x); pc(c);
}template<typename T,typename ...Arg>void write(T x,Arg ...arg){
write(x); write(arg...);
}inline _IfD pow_10(_IfD x){
_IfD base=10,ans=1;
while(x) ans*=((x&1)?base:1),base*=base,x>>=1;
return ans;
}template<typename T>void readd(T &w){
w=0; _IfD x=0,cnt=0; bool f=1; char ch=gc();
for(;ch<=32;ch=gc()); if(ch=='-')f=0;
for(;'0'<=ch && ch<='9';ch=gc()) x=(x<<1)+(x<<3)+(ch^48);
w=(T)(f?x:-x);
if(ch!='.') return; x=0,ch=gc();
for(;'0'<=ch && ch<='9';ch=gc(),++cnt) x=(x<<1)+(x<<3)+(ch^48);
T tmp=(T)(x/(T)pow_10(cnt));
w=w+(T)(f?tmp:-tmp);
}template<typename T,typename ...Arg>void readd(T &w,Arg &...arg){
readd(w); readd(arg...);
}void readstr(string &s){
char ch=gc();
while(ch!='\n' && ch!=' ') s+=ch,ch=gc();
}void putstr(string s){
int i=0; while(i<s.size()) pc(s[i++]);
}
template<typename T>inline T qmax(_cst T &a,_cst T &b){return a>b?a:b;}
template<typename T,typename ...Arg>inline T qmax(_cst T &a,_cst T &b,_cst Arg &...arg){return qmax(a,qmax(b,arg...));}
template<typename T>inline T qmin(_cst T &a,_cst T &b){return a<b?a:b;}
template<typename T,typename ...Arg>inline T qmin(_cst T &a,_cst T &b,_cst Arg &...arg){return qmin(a,qmin(b,arg...));}
template<typename T>inline void qswap(T &a,T &b){a+=b,b=a-b,a-=b;}
using namespace std;
const int MAXN=200005;
int n,tot=0;
vector<int> E[MAXN];
struct Node{int dfn,sze,r,b,id;}a[MAXN];
inline bool cmp1(const Node &a,const Node &b){
if(a.r!=b.r) return a.r<b.r;
if(a.b!=b.b) return a.b<b.b;
return a.dfn+a.sze<b.dfn+b.sze;
}
inline bool cmp2(const Node &a,const Node &b){
if(a.b!=b.b) return a.b<b.b;
return a.dfn+a.sze<b.dfn+b.sze;
}
void dfs(int u,int fa){
a[u].dfn=++tot,a[u].sze=1;
for(int v:E[u]) if(v!=fa) dfs(v,u),a[u].sze+=a[v].sze; // 求 dfn 序,以及算子树大小
}
int tr[MAXN<<2]; // 线段树维护单点+1、区间求和
void upd(int p,int l,int r,int t,int k){
if(l==r) return tr[p]+=k,void();
int mid=(l+r)>>1;
if(t<=mid) upd(p<<1,l,mid,t,k);
else upd(p<<1|1,mid+1,r,t,k);
tr[p]=tr[p<<1]+tr[p<<1|1];
}
int query(int p,int l,int r,int st,int en){
if(l>en || r<st) return 0;
if(st<=l && r<=en) return tr[p];
int mid=(l+r)>>1;
return query(p<<1,l,mid,st,en)+query(p<<1|1,mid+1,r,st,en);
}
int ans[MAXN];
void cdq(int l,int r){ // cdq 分治
if(l==r) return;
int mid=(l+r)>>1;
cdq(l,mid),cdq(mid+1,r); // 先递归左右两边
sort(a+l,a+mid+1,cmp2); // 排序
sort(a+mid+1,a+r+1,cmp2);
int i=l;
for(int j=mid+1;j<=r;j++){ // 双指针算贡献
while(i<=mid && a[i].b<=a[j].b) upd(1,1,n,a[i].dfn,1),i++; // 插入 dfn 的位置
ans[a[j].id]+=query(1,1,n,a[j].dfn+1,a[j].dfn+a[j].sze-1); // 查询子树内满足条件的数量
}
for(int j=l;j<i;j++) upd(1,1,n,a[j].dfn,-1); // 清空线段树
}
signed main(){
read(n);
for(int i=1;i<n;i++){
int u,v; read(u,v);
E[u].push_back(v);
E[v].push_back(u);
}
dfs(1,0); // 预处理
for(int i=1;i<=n;i++) read(a[i].r,a[i].b),a[i].id=i;
sort(a+1,a+1+n,cmp1); // 按照 r,b,dfn 排序
cdq(1,n); // cdq 分治
for(int i=1;i<=n;i++)
if(ans[i]!=0) write(ans[i]); // 输出
return flush(),0;
}