首页 > 其他分享 >特殊四维偏序—星之河

特殊四维偏序—星之河

时间:2022-11-30 22:55:09浏览次数:33  
标签:偏序 10 le 四维 text mid 星之河 节点

特殊四维偏序-星之河

「DTOI-2」星之河

题目背景

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

题目描述

星之统治者有一个星盘,其可以被抽象为一棵根节点为 \(1\) 的树。树上每个节点 \(i\) 有一颗红星、一颗蓝星,亮度分别记为 \(\text{Red}_i,\text{Blue}_i\)。

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

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

输入格式

第一行两个整数分别表示 \(n\)。

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

接下来 \(n\) 行每行两个整数分别表示 \(\text{Red}_i, \text{Blue}_i\)。

输出格式

每个答案非 \(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\)。
对于节点 $5 $ 至 \(10\),没有小于等于他的子节点,因此不输出。

数据范围

\(\textbf{Subtask}\) \(n\le\) 特殊性质 总分数
\(1\) \(1000\) \(10\)
\(2\) \(5\times 10^4\) \(20\)
\(3\) \(10^5\) \(-200\le \text{Red}_i, \text{Blue}_i \le 200\) \(20\)
\(4\) \(2\times 10^5\) 树的形态是链 \(20\)
\(5\) \(2\times 10^5\) \(30\)

对于所有数据,保证 \(n \le 2\times 10^5\),\(-10^9 \le \text{Red}_i, \text{Blue}_i \le 10^9\)。

题解

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

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

假设我们定义一个结构体

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

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

\[a[i].le\le a[j].le\le a[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].r\)的\(k\)的个数

小小差分一下就有\(ans[i]=w(a[i].ri,i)-w(a[i].le-1,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();
}

标签:偏序,10,le,四维,text,mid,星之河,节点
From: https://www.cnblogs.com/oierpyt/p/16940087.html

相关文章

  • 【洛谷P3810】 【模板】三维偏序(陌上花开)
    CDQ是一中思想,用来求点对数列。定义\(solve(l,r)\)用来求\([l,r]\)区间的数对,那么先递归处理\(solve(l,mid)\),然后考虑前半段对后半段的影响,然后再递归处理后半段\(sol......
  • 记录一下某一个log的三维偏序
    求\(a_i<a_j,b_i<b_j,c_i<c_j\)的数对个数。先把三个二维偏序拆出来跑一遍。然后看贡献:三维偏序:一个算了三次。二维:一个算了一次。剩下的:没算。然后发现三维+二维=......
  • 2815. 三维偏序
    题目链接2815.三维偏序给定\(n\)个元素(编号\(1\simn\)),其中第\(i\)个元素具有\(a_i,b_i,c_i\)三种属性。设\(f(i)\)表示满足以下\(4\)个条件:\(a_j\lea......
  • n维偏序 方法记录
    题解首先我们要对一个地点能否到达建立认知:一个地点能到达不仅仅是能从它的上一个点或上上个点跳到,而是能从第一个点开始跳一路跳到。就好比说,咱吃了6个包子吃饱了,但咱......
  • CDQ&整体二分-三维偏序(陌上花开)
    题面本文讲cdq,整体二分的思路与做法。=分治VS数据结构其实维度这一方面,空间几何可以是维度,像时间这样有规定顺序的词语也可能是维度。cdq三维偏序,一般可以用一维一维的......
  • 模拟赛 d (扫描线,三维偏序,线段树合并,并查集,线段树上二分)
    PRO题目大意:给定$N$个矩形,求连通块个数。($1\leqN,x_1,x_2,y-1,y_2\leq100000$)SOL乍一看就能知道是扫描线,不过这题的细节恐怖的要命。(std同样看不懂,自己魔改了一......
  • 「JOISC 2016 Day 1」俄罗斯套娃(二维偏序)
    「JOISC2016Day1」俄罗斯套娃思路清奇的呀,先在坐标轴上画图(R为横坐标,H为纵坐标),然后发现每个询问之间没有影响,考虑离线处理,因为询问的要求是选择>=R的,所以把横坐标从大......