特殊四维偏序—星之河

特殊四维偏序-星之河

「DTOI-2」星之河

题目背景

星稀河影转,霜重月华孤。

题目描述

星之统治者有一个星盘,其可以被抽象为一棵根节点为 1 的树。树上每个节点 i 有一颗红星、一颗蓝星,亮度分别记为 Redi,Bluei

现在,星之统治者想要知道,对于每个节点 x,其子树内(不包括该节点)有多少节点满足:其红星亮度小于等于 x 的红星亮度,且其蓝星亮度小于等于 x 的蓝星亮度。

你需要按编号顺序依次输出每个节点的答案。为减少输出量,如果答案为 0 则不必输出。

输入格式

第一行两个整数分别表示 n

接下来 n1 行每行两个正整数 u,v,表示存在 (u,v) 这条树边。

接下来 n 行每行两个整数分别表示 Redi,Bluei

输出格式

每个答案非 0 的节点一行,每行一个整数表示答案。

样例 #1

样例输入 #1

10
2 1
3 1
4 3
5 1
6 4
7 2
8 2
9 4
10 3
3 1
2 4
-3 3
4 -2
-2 3
-3 -6
-5 -1
-4 -7
-5 -1
-7 -7

样例输出 #1

5
2
3
1

提示

样例解释

对于节点 1,小于等于他的子节点有 6,7,8,9,10,因此输出 5
对于节点 4,小于等于他的子节点有 6,因此输出 1
对于节点 510,没有小于等于他的子节点,因此不输出。

数据范围

Subtask n 特殊性质 总分数
1 1000 10
2 5×104 20
3 105 200Redi,Bluei200 20
4 2×105 树的形态是链 20
5 2×105 30

对于所有数据,保证 n2×105109Redi,Bluei109

题解

纪念我考场上想出了正解却不敢写

这玩意在树上貌似不好搞,DP之类的都不行,考虑转移到序列上,那么我们把这棵树拍一个DFS序,然后再看这个问题

假设我们定义一个结构体

struct node{  
    int le,ri,b,r,id;
}a[N<<1];

分别存节点的DFS序的两个出现位置的权值,蓝色权值,红色权值以及节点id,那么我们的问题就变成了对于每一个i,统计满足

a[i].lea[j].lea[i].ri,a[j].b<a[i].b,a[j].r<a[i].r

的点的数量,假设我们记w(i,j)表示满足a[k].le<i,a[k].b<a[j].b,a[k].r<a[j].rk的个数

小小差分一下就有ans[i]=w(a[i].ri,i)w(a[i].le1,i)

那么对于w的求法,明眼人都看得出来,三维偏序

所以说,这道题本质上就是一个拍成DFS序之后的特殊四维偏序,这个四维偏序可以转化为两个三维偏序,也可以在累计答案的时候直接差分掉

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 200050
#define M 600050
#define re register
using namespace std;
struct node{
	int le,ri,b,r,id;
}a[N<<1];
int ans[N],num,head[N],ver[M],nxt[M],tot,c[N],n,m;
inline void add(int u,int v){
	nxt[++tot]=head[u],ver[head[u]=tot]=v;
}
void dfs(int u,int f){
	a[u].le=++num;
	for(int i=head[u];i;i=nxt[i]){
		int v=ver[i];
		if(v!=f)dfs(v,u);
	}
	a[u].ri=num;
}
inline bool cmp1(node a,node b){
	if(a.b==b.b){
		if(a.r==b.r)return a.le>b.le;;
		return a.r<b.r;
	}
	return a.b<b.b;
}
inline bool cmp2(node a,node b){
	if(a.r==b.r)return a.ri<b.ri;
	return a.r<b.r;
}
inline void Add(int x,int k){while(x<=n)c[x]+=k,x+=x&-x;}
inline int ask(int x){int ans=0;while(x)ans+=c[x],x-=x&-x;return ans;}
inline void CDQ(int l,int r){
	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 j=l;
	for(re int i=mid+1;i<=r;i++){
		while(a[j].r<=a[i].r&&j<=mid)Add(a[j++].le,1);
		ans[a[i].id]+=ask(a[i].ri)-ask(a[i].le-1);
	}
	for(int i=l;i<j;i++)Add(a[i].le,-1);
}
inline void init(){
	scanf("%d",&n);
	for(re int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
	dfs(1,0);
	for(re int i=1;i<=n;i++)scanf("%d%d",&a[i].b,&a[i].r);
	for(re int i=1;i<=n;i++)a[i].id=i;
	sort(a+1,a+n+1,cmp1);
	CDQ(1,n);
	for(re int i=1;i<=n;i++)if(ans[i])printf("%d\n",ans[i]);
}
int main(){
	init();
}
posted @   spdarkle  阅读(75)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示