descriptionsol現在有一棵二叉樹,所有非葉子節點都有兩個孩子。在每個葉子節點上有乙個權值(有n個葉子節點,滿足這些權值為1…n的乙個排列)。可以任意交換每個非葉子節點的左右孩子。
要求進行一系列交換,使得最終所有葉子節點的權值按照遍歷序寫出來,逆序對個數最少。
input
第一行n
下面每行,乙個數x
如果x==0,表示這個節點非葉子節點,遞迴地向下讀入其左孩子和右孩子的資訊,
如果x!=0,表示這個節點是葉子節點,權值為x
1<=n<=200000
output
一行,最少逆序對個數
sample input30
0312
sample output
1
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...