大小接近的點對 (樹狀陣列 離散化)

2021-09-19 03:35:53 字數 1321 閱讀 1200

題目描述

一天,chika 對大小接近的點對產生了興趣,她想搞明白這個問題的樹上版本,你能幫助她嗎?chika 會給 你一棵有根樹,這棵樹有 n 個結點,被編號為 1 n,1 號結點是根。每個點有乙個權值,i 號結點的權值為 a[i]。如果 u 是 v 的祖先結點,並且 abs(a[u]−a[v]) ≤k,那麼 (u,v) 被稱作乙個「** 大小接近的點對 **」。 對於樹上的每個結點 i,你都需要計算以其為根的子樹中的「大小接近的點對」的數量。你需要知道:  

(1) abs(x) 代表 x 的絕對值。  

(2) 每個結點都是其自身的祖先結點. 

輸入輸入檔案的第一行包含兩個整數 n (1≤n≤105) 和 k (1≤k≤109),代表樹中結點總數, 以及「大小接近的點對」的大小之差的上界。  

第二行包含 n 個整數,第 i 個整數是 a[i] (1≤ a[i] ≤109),代表 i 號結點的權值。  

第三行包含 n−1 個整數,第 i 個整數是 i+1 號結點的父結點。 

輸出輸出應該包含n行,每一行包括乙個整數。第i行的整數代表以i為根的子樹中的「大小接近的點對」的數量。

樣例輸入 copy

7 5

2 4 4 1 4 6 4

1 2 3 1 2 3

樣例輸出 copy

19115

1111

思路:這道題如果暴力的做法就是遍歷樹,每次返回乙個陣列,然後二分求合法答案的個數tle。zdw大佬用樹狀陣列代替的返回的陣列,核心思想就是先將所有數離散化,記錄他們的位置,然後遍歷樹的時候,首先先進行樹狀陣列的查詢操作,也就是把以前樹種的」合法答案「(其實是不合法的,不在這個節點的子樹上),然後把這個點的值加入樹狀陣列,繼續遍歷樹,返回到這個節點時,再進行樹狀陣列的查詢(它的子樹都加入到樹狀中了),然後減去第一次查詢的結果即可。

**如下:

#include#define ll long long

#define n 300010

using namespace std;

vectorv[100010];

mapu;

int n,k;

ll a[100010],ans[100010],l[n],r[n],sum[n];

ll low_bit(ll x)

void add(ll x)

ll dfs(int x)

for(int i=1; ill sum=dfs(1);//跑一遍樹

for(int i=1; i<=n; i++)

printf("%lld\n",ans[i]);

return 0;

}

樹狀陣列 (離散化 樹狀陣列 求逆序對)

sample test s input 52 3 1 5 4 output 3 題目大意 求逆序對的個數 題目分析 求逆序對有很多方法,比如說用合併排序 分治 樹狀陣列 線段樹,甚至連暴力 氣泡排序 也可以做,但是要注意會不會超時。這裡就講一下樹狀陣列的方法,這一題最有意思的是離散化的方法,這個方法...

離散化 樹狀陣列

題目描述 erwin最近對一種叫 thair 的東西巨感興趣。在含有n個整數的序列a1,a2 an中,三個數被稱作 thair 當且僅當i求乙個序列中 thair 的個數。輸入格式 開始乙個正整數n,以後n個數a1 an。輸出格式 thair 的個數 思路 列舉中間的數字,求排在它前面,小於它的有幾...

逆序對 離散樹狀陣列

求逆序對有三種以上方法 1 離散樹狀陣列,2 線段樹,3 歸併排序 今天做了下洛谷的p1908逆序對 1 一開始用樹狀陣列,一直re,後來在發現自己一直忽略離散化。include include using namespace std const int maxn 400000 5 typedef ...