【题解】P8575 「DTOI-2」星之河

P8575】题解

一:【题面】

二:【解法】

每个节点打上dfn序列
每个节点有属性{a,b,c}表{红星亮度,蓝星亮度,dfn序}和siz

之后问题等价于
对于每个节点i求出多少节点j同时满足

  • a[j]<=a[i]
  • b[j]<=b[i]
  • c[i]<c[j]<=c[i]+siz[i]-1
    做CDQ分治求三维偏序,树状数组求区间和即可

三:【代码】

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
vector<int> mp[N];
int cnt=0;
int dfn[N],siz[N];
void dfs(int u,int fa){
	dfn[u]=++cnt;
	siz[u]=1;
	for(auto v:mp[u]){
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
	}
}
struct node{
	int id,a,b,c;
	int ans;
}q[N<<1];
bool cmpa(node x,node y){
	if(x.a!=y.a) return x.a<y.a;
	if(x.b!=y.b) return x.b<y.b;
	return x.c>y.c;
}
bool cmpb(node x,node y){
	if(x.b!=y.b) return x.b<y.b;
	return x.c>y.c;
}
int tree[N];
void update(int x,int d){
	while(x<N){
		tree[x]+=d;
		x+=x&-x;
	}
}
int query(int x){
	int res=0;
	while(x){
		res+=tree[x];
		x-=x&-x;
	}
	return res;
}
void CDQ(int l,int r){
	if(l==r) return ;
	int mid=l+r>>1;
	CDQ(l,mid);CDQ(mid+1,r);
	sort(q+l,q+mid+1,cmpb);sort(q+mid+1,q+r+1,cmpb);
	int i=l,j=mid+1;
	while(j<=r){
		while(i<=mid&&q[i].b<=q[j].b){
			update(q[i].c,1);
			i++;
		}
		q[j].ans+=query(q[j].c+siz[q[j].id]-1)-query(q[j].c);
		j++;
	}
	for(int k=l;k<i;k++){
		update(q[k].c,-1);
	}
}
int ans[N];
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int n;cin>>n;
	for(int i=1;i<n;i++){
		int a,b;cin>>a>>b;
		mp[a].push_back(b);
		mp[b].push_back(a);
	}
	dfs(1,1);
	
	
	int idx=0;
	for(int i=1;i<=n;i++){
		int b,c;cin>>b>>c;
		q[++idx]={i,b,c,dfn[i],0};
	}	
	
	sort(q+1,q+1+idx,cmpa);
	CDQ(1,idx);
	for(int i=1;i<=idx;i++) ans[q[i].id]+=q[i].ans;
	for(int i=1;i<=n;i++){
		if(ans[i]) cout<<ans[i]<<"\n";
	}
	return 0;
}
//c只会对<c的造成影响,所以要逆序排
posted @ 2025-12-26 18:10  Ming3398  阅读(13)  评论(0)    收藏  举报