bzoj2212(線段樹合併)

2021-09-04 02:04:20 字數 2138 閱讀 9201

description

現在有一棵二叉樹,所有非葉子節點都有兩個孩子。在每個葉子節點上有乙個權值(有n個葉子節點,滿足這些權值為1…n的乙個排列)。可以任意交換每個非葉子節點的左右孩子。

要求進行一系列交換,使得最終所有葉子節點的權值按照遍歷序寫出來,逆序對個數最少。

input

第一行n

下面每行,乙個數x

如果x==0,表示這個節點非葉子節點,遞迴地向下讀入其左孩子和右孩子的資訊,

如果x!=0,表示這個節點是葉子節點,權值為x

1<=n<=200000

output

一行,最少逆序對個數

sample input30

0312

sample output

1

sol

utio

nsolution

soluti

on:裸的線段樹合併

只要考慮左子樹右子樹互相的影響即可

#include

using

namespace std;

#define rep(i,j,k) for(int i = j;i <= k;++i)

#define repp(i,j,k) for(int i = j;i >= k;--i)

#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)

#define p pair

#define pil pair

#define pli pair

#define pll pair

#define pb push_back

#define pc putchar

#define mp make_pair

#define file(k) memset(k,0,sizeof(k))

#define ll long long

intrd()

while

(c >=

'0'&& c <=

'9') num = num*

10+c-

48,c =

getchar()

;if(flag)

return num;

else

return

-num;

}ll ans1,ans2;

int n,t,cnt;

int ch[

401000][

2];int val[

401000

],rt[

401000];

int ls[

16001000

],rs[

16001000

],num[

16001000];

int tmp[

201000

],tot;

void

init

(int x)

intmerge

(int x,

int y)

void

add(

int&root,

int l,

int r,

int pl)

ll work

(int x)

else

add(rt[x],1

,tot,val[x]);

return ans;

}int

main()

else

init

(++t)

;sort

(tmp+

1,tmp+tot+1)

; tot =

unique

(tmp+

1,tmp+tot+1)

- tmp -1;

rep(i,

1,t)

if(val[i]

) val[i]

=lower_bound

(tmp+

1,tmp+tot+

1,val[i]

)- tmp;

printf

("%lld\n"

,work(1

));return0;

}

bzoj 2212(線段樹合併)

傳送門 題解 權值線段樹從下往上合併,每個點統計兩個兒子中某乙個交換 不交換的答案,取min後加到總答案中。不禁讓人想起cdqz challenge 13 p.s.形態樹開兩倍空間,因為這種讀入方式肯定會讀成一棵滿二叉樹 不管存不存在子節點先加了時間戳 另外,定義變數要搞清楚哪個是輸入的形態樹,哪個...

BZOJ2212 二叉樹 線段樹合併

這道題給人的第一感覺像是樹形 include define maxn 400010 define reg register define cmin x,y x y using namespace std int n,tot,w maxn lson maxn rson maxn root maxn 原...

BZOJ 4756 線段樹合併(線段樹)

思路 1.最裸的線段樹合併 2.我們可以觀察到子樹求乙個東西 那我們直接dfs序好了 入隊的時候統計一下有多少比他大的 出的時候統計一下 減一下 搞定 線段樹合併 by siriusren include include include using namespace std const int n...