P8575 「DTOI-2」星之河 题解

题目传送门

前置知识

CDQ 分治 | 权值树状数组及应用

解法

增加一维为 DFS 序,然后就转化成了三维偏序问题,可以使用 CDQ 分治求解。

此时等价于求 \(red_{j} \le red_{i},blue_{j} \le blue_{i},dfn_{i}<dfn_{j} \le out_{i}\)\(j\) 的数量。第三个限制条件前缀和维护即可。

注意按 DFS 序排序时,为保证子树内部节点能更新到根节点,需要降序排序。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
struct node
{
	int a,b,dfn,out,id;
}a[200010];
int ans[200010],tot=0;
vector<int>e[200010];
bool cmpb(node a,node b)
{
	return (a.b==b.b)?(a.dfn>b.dfn):(a.b<b.b);
}
bool cmpa(node a,node b)
{
	return (a.a==b.a)?cmpb(a,b):(a.a<b.a);
}
void add(int u,int v)
{
	e[u].push_back(v);
}
void dfs(int x,int fa)
{
	tot++;
	a[x].dfn=tot;
	for(int i=0;i<e[x].size();i++)
	{
		if(e[x][i]!=fa)
		{
			dfs(e[x][i],x);
		}
	}
	a[x].out=tot;
}
struct BIT
{
	int dfn[200010];
	int lowbit(int x)
	{
		return (x&(-x));
	}
	void add(int n,int x,int val)
	{
		for(int i=x;i<=n;i+=lowbit(i))
		{
			dfn[i]+=val;
		}
	}
	int getsum(int x)
	{
		int ans=0;
		for(int i=x;i>=1;i-=lowbit(i))
		{
			ans+=dfn[i];
		}
		return ans;
	}
}T;
void cdq(int l,int r,int k)
{
	if(l==r)
	{
		return;
	}
	int mid=(l+r)/2,x,y;
	cdq(l,mid,k);
	cdq(mid+1,r,k);
	sort(a+l,a+mid+1,cmpb);
	sort(a+mid+1,a+r+1,cmpb);
	for(x=l,y=mid+1;y<=r;y++)
	{
		for(;a[x].b<=a[y].b&&x<=mid;x++)
		{
			T.add(k,a[x].dfn,1);
		}
		ans[a[y].id]+=T.getsum(a[y].out)-T.getsum(a[y].dfn);
	}
	x--;
	for(int i=l;i<=x;i++)
	{
		T.add(k,a[i].dfn,-1);
	}
}
int main()
{
	int n,u,v,i;
	cin>>n;
	for(i=1;i<=n-1;i++)
	{
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	dfs(1,0);
	for(i=1;i<=n;i++)
	{
		cin>>a[i].a>>a[i].b;
		a[i].id=i;
	}
	sort(a+1,a+1+n,cmpa);
	cdq(1,n,n);
	for(i=1;i<=n;i++)
	{
		if(ans[i]!=0)
		{
			cout<<ans[i]<<endl;
		}
	}
	return 0;
}	
posted @ 2024-08-09 15:21  hzoi_Shadow  阅读(28)  评论(0编辑  收藏  举报
扩大
缩小