1. 程式人生 > >dfs序+線段樹--青出於藍勝於藍

dfs序+線段樹--青出於藍勝於藍

https://nanti.jisuanke.com/t/20690

武當派一共有 nn 人,門派內 nn 人按照武功高低進行排名,武功最高的人排名第 11,次高的人排名第 22,... 武功最低的人排名第 nn。現在我們用武功的排名來給每個人標號,除了祖師爺,每個人都有一個師父,每個人可能有多個徒弟。

我們知道,武當派人才輩出,連祖師爺的武功都只能排行到 pp。也就是說徒弟的武功是可能超過師父的,所謂的青出於藍勝於藍。

請你幫忙計算每個人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟....)中,有多少人的武功超過了他自己。

輸入格式

輸入第一行兩個整數 n,p(1≤n≤100000,1≤p≤n)n,

p(1n100000,1pn)

接下來 n−1n1 行,每行輸入兩個整數 u,v(1≤u,v≤n)u,v(1u,vn),表示 uu 和 vv 之間存在師徒關係。

輸出格式

輸出一行 nn 個整數,第 ii 個整數表示武功排行為 ii的人的子弟有多少人超過了他。

通過求dfs序,將子樹上的問題轉化為序列上的問題,然後用線段樹求小於某個數的數的個數。

#include <cstdio>

#include <iostream>

#include <vector>

#include <queue>

usingnamespace std

;

#define lc (rt << 1)

#define rc (rt << 1 | 1)

#define mid (l + r) / 2

const int maxn = 1e5 + 5;

vector<int> mp[maxn];

int f[maxn];

int te = 1;

int s[maxn],t[maxn];

int mmin[maxn << 2],mmax[maxn << 2];

int pre[maxn];

int prep = 1;

int ans[maxn];

int n,p;

void dfs(int p)

{

    s[p] = ++te;

    pre[prep ++] = p;

    for (int i = 0; i < mp[p].size(); i ++) {

        if(s[mp[p][i]] == 0) {

            dfs(mp[p][i]);

        }

        else f[p] = mp[p][i];

    }

    t[p] = te;

}

void init(int l,int r,int rt)

{

    if(l == r){

        mmin[rt] = mmax[rt] = pre[l];

        return;

    }

    init(l, mid, lc);

    init(mid + 1, r, rc);

    mmax[rt] = max(mmax[lc],mmax[rc]);

    mmin[rt] = min(mmin[lc],mmin[rc]);

}

int querymmin(int ql,int qr,int l,int r,int rt)

{

    if(ql <= l && r <= qr){

       return mmin[rt];

    }

    int ans = maxn;

    if(ql <= mid) ans = min(ans,querymmin(ql, qr, l, mid , lc));

    if(mid < qr) ans = min(ans,querymmin(ql, qr, mid + 1, r, rc));

    return ans;

}

int querymmax(int ql,int qr,int l,int r,int rt)

{

    if(ql <= l && r <= qr){

        return mmax[rt];

    }

    int ans = 0;

    if(ql <= mid) ans = max(ans,querymmax(ql, qr, l, mid , lc));

    if(mid < qr) ans = max(ans,querymmax(ql, qr, mid + 1, r, rc));

    return ans;

}

int querycnt(int ql,int qr,int l,int r,int rt,int x)//求區間中比x小的數的個數

{

    if(ql <= l && r <= qr){

        if(querymmax(ql, qr, l, r, rt) < x ) return r - l + 1;

        else {

            if(querymmin(ql, qr, l, r, rt) >= x)return 0;

            else return querycnt(ql, qr, l, mid, lc, x) + querycnt(ql, qr, mid + 1, r, rc, x);

        }

    }

    int ans = 0;

    if(ql <= mid){

         ans += querycnt(ql,qr,l,mid,lc,x);

    }

    if(mid < qr){

          ans += querycnt(ql,qr,mid + 1,r,rc,x);

    }

    return ans;

}

int main()

{

    int a,b;

    f[p] = -1;

    scanf("%d%d",&n,&p);

    for (int i = 0; i < n - 1; i ++) {

        scanf("%d%d",&a,&b);

        mp[a].push_back(b);

        mp[b].push_back(a);

    }

    dfs(p);

    init(1, n, 1);

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

        ans[pre[i]] = querycnt(s[pre[i]] - 1, t[pre[i]] - 1, 1, n,1 ,pre[i]);

//  printf("l = %d ,r = %d ,less than %d ,cnt = %d\n",s[pre[i]] - 1, t[pre[i]] - 1,pre[i],ans[pre[i]]);

    }

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

        printf("%d",ans[i]);

        if(i == n) printf("\n");

        else printf(" ");

    }

return 0;

}



相關推薦

dfs+線段--青出於藍

https://nanti.jisuanke.com/t/20690 武當派一共有 nn 人,門派內 nn 人按照武功高低進行排名,武功最高的人排名第 11,次高的人排名第 22,... 武功最低的人排名第 nn。現在我們用武功的排名來給每個人標號,除了祖師爺,每個人

[BZOJ 3306]dfs+線段+倍增)

最小 get == 支持 如果 space amp ring zoj Description 給定一棵大小為 n 的有根點權樹,支持以下操作: • 換根 • 修改點權 • 查詢子樹最小值 Solution 單點修改子樹查詢

HDOJ5692解題報告【dfs+線段

註意 表示 pre fine efi tree using push cnblogs 題目地址:   http://acm.hdu.edu.cn/showproblem.php?pid=5692 題目概述:   中文題面就不贅述了。 大致思路:   這個題給出的是一棵樹,我

codevs1228 (dfs+線段)

ret size str clas r+ cstring print sizeof scanf 總結: 第一次遇到dfs序的問題,對於一顆樹,記錄節點 i 開始搜索的序號 Left[i] 和結束搜索的序號 Righti[i],那麽序號在 Left[i] ~ Right[

Codeforces Round #442 (Div. 2) 877E - Danil and a Part-time Job dfs+線段

pac upd style init problem def ios const clas Codeforces Round #442 (Div. 2) 877E - Danil and a Part-time Job emmmm第一次見的東西感覺都好神奇 #inclu

Codeforces 877E Danil and a Part-time Job(dfs + 線段

struct problem 區間求和 %d blank turn force ref upd 題目鏈接 Danil and a Part-time Job 題意 給出一系列詢問或者修改操作    pow x表示把以x為根的子樹的所有結點的狀態取反(0變1,1

HDU 3974 Assign the task(DFS+線段

string ssi 組成 ase target 區間 兩張 img lan 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=3974 題意:n名員工組成一棵樹,分配任務給其中一名員工,那麽他和他的手下(就是該節點的全部子節點

【XSY2667】摧毀圖狀 貪心 堆 DFS 線段

printf con 線段 string def body 暴力 clu while 題目大意   給你一棵有根樹,有\(n\)個點。還有一個參數\(k\)。你每次要刪除一條長度為\(k\)(\(k\)個點)的祖先-後代鏈,問你最少幾次刪完。現在有\(q\)個詢問,每次給你

CoderForces343D:Water Tree(dfs+線段&&特殊處理)

down operation ace sta 更改 lis contains AR pil Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex

BZOJ.4817.[SDOI2017]點塗色(LCT DFS 線段)

HP date amp num 貢獻 pla AR name log 題目鏈接 1.2裸樹剖,但是3.每個點的答案val很不好維護。。 如果我們把同種顏色的點劃分到同一連通塊中,那麽向根染色的過程就是Access()! 最初所有點間都是虛邊,相同顏色點用實邊相連。一條邊由實

【Bzoj3252】攻略(dfs+線段

esc long modify down 影響 link truct etc tchar Description 題目鏈接 Solution 可以想到,每次肯定是拿最大價值為最優 考慮改變樹上一個點的值,只會影響它的子樹,也就是dfs序上的一個區間, 於是可以以dfs序建線

CodeForces 838B - Diverging Directions - [DFS+線段]

dex return nes clu scan itl 來講 clock spec 題目鏈接:http://codeforces.com/problemset/problem/838/B You are given a directed weighted graph wit

Random Numbers Gym - 101466K dfs+線段

%d follow with == comm nodes lov linker main Tamref love random numbers, but he hates recurrent relations, Tamref thinks that mainstream

BZOJ 4043 [HAOI2015]樹上操作 dfs 線段

.com clas use 兩個 pro sample com from lse $ \Rightarrow $ 戳我進BZOJ原題 $ \Rightarrow $ 戳我進洛谷原題 [HAOI2015]樹上操作 Time Limit: 10 Sec Memory Limi

BZOJ3252 攻略(貪心+dfs+線段

ont str har using fin namespace bzoj3 n) -i   考慮貪心,每次選價值最大的鏈。選完之後對於鏈上點dfs序暴力修改子樹。因為每個點最多被選一次,復雜度非常正確。 #include<iostream> #include

[NOIP10.6模擬賽]2.equation題解--DFS+線段

一道 freopen 線段樹 gist his struct 樹狀數組 10.6 fread 題目鏈接: 咕 閑扯: 終於在集訓中敲出正解(雖然與正解不完全相同),開心QAQ 首先比較巧,這題是\(Ebola\)出的一場模擬賽的一道題的樹上強化版,當時還口胡出了那題的題解

hdu5692 Snacks dfs+線段

mathjax \n class == -- c++ tin blank color 題目傳送門 題目大意:給出一顆樹,根節點是0,有兩種操作,一是修改某個節點的value,二是查詢,從根節點出發,經過 x 節點的路徑的最大值。 思路:用樹狀數組寫發現還是有些麻煩,最後用線

天天愛跑步[lca][dfs][線段動態開點]

傳送門 大家都寫的差分,我太菜了看不懂啊 與是這成了我練習暴力資料結構的好機會... 我們發現,當往上走時,一個點對答案有貢獻, dep[s] - dep[x] = time[x] 往下走 dep[t] - dep[x] = len - time[x] 於是我想,把de

HDU-5692-Snacks(DFS+線段,單點修改,區間查詢)

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5692 Problem Description 百度科技園內有n 個零食機,零食機之間通過n−1 條路相互連通。每個零食機都有一個值v ,表示為小度熊提供零食的價值。 由於零

zoj 3686 - A Simple Tree Problem (dfs+線段區間更新)

Given a rooted tree, each node has a boolean (0 or 1) labeled on it. Initially, all the labels are 0. We define this kind of operation: given a