1. 程式人生 > >BZOJ 2212 線段樹啟發式合併

BZOJ 2212 線段樹啟發式合併

簡略題意:現在有一棵二叉樹,所有非葉子節點都有兩個孩子。在每個葉子節點上有一個權值(有n個葉子節點,滿足這些權值為1..n的一個排列)。可以任意交換每個非葉子節點的左右孩子。要求進行一系列交換,使得最終所有葉子節點的權值按照遍歷序寫出來,逆序對個數最少。

考慮題中的唯一操作,交換兩個孩子。
對每個節點考慮兩個孩子對答案的貢獻:左孩子的貢獻 + 右孩子的貢獻 + 左孩子比右孩子大產生的貢獻。
交換兩個孩子只會使得第三種貢獻變化,且只對當前節點有影響。
因此我們只需要考慮如何計算逆序對。

對節點建權值線段樹,考慮將左右孩子的線段樹合併時,不反轉的情況下,每次統計左孩子對右孩子的影響的數量,然後遞迴合併下去。反轉的情況下就是考慮右孩子對左孩子的影響。
其實這裡本質上和cdq分治是一樣的,可以做到統計貢獻的不重不漏。

#include <bits/stdc++.h>
#define all(x) x.begin(), x.end()
using namespace std;

const int maxn = 4400000;
int n;
int cid;

int root[maxn], l[maxn], r[maxn], v[maxn];
struct Seg {
    int l, r, sum;
} tr[maxn];

void pushup(int x) {
    tr[x].sum = tr[tr[x].l].sum + tr[tr[x].r].sum;
}

int update(int
pos, int l, int r) { int x = ++cid; int m = l + r >> 1; if(l == r) { tr[x].sum = 1; return x; } if(pos <= m) tr[x].l = update(pos, l, m); else tr[x].r = update(pos, m+1, r); pushup(x); return x; } int sz = 1; void read(int x
) { scanf("%d", &v[x]); if(v[x] == 0) { l[x] = ++sz; read(l[x]); r[x] = ++sz; read(r[x]); } else { root[x] = update(v[x], 1, n); } } long long ans = 0, s1 = 0, s2 = 0; int mergetree(int x, int y, int tp) { if(!x) return y; if(!y) return x; if(tp == 1) { s1 += 1LL * tr[tr[x].r].sum * tr[tr[y].l].sum; s2 += 1LL * tr[tr[x].l].sum * tr[tr[y].r].sum; } else { s2 += 1LL * tr[tr[x].r].sum * tr[tr[y].l].sum; s1 += 1LL * tr[tr[x].l].sum * tr[tr[y].r].sum; } tr[x].l = mergetree(tr[x].l, tr[y].l, tp); tr[x].r = mergetree(tr[x].r, tr[y].r, tp); pushup(x); return x; } void dfs(int x) { if(!x) return ; dfs(l[x]), dfs(r[x]); if(!v[x]) { s1 = s2 = 0; if(tr[root[l[x]]].sum > tr[root[r[x]]].sum) root[x] = mergetree(root[l[x]], root[r[x]], 1); else root[x] = mergetree(root[r[x]], root[l[x]], 2); ans += min(s1, s2); } } void init() { cid = 0; } int main() { init(); scanf("%d", &n); read(1); dfs(1); printf("%lld\n", ans); return 0; }

相關推薦

BZOJ 2212 線段啟發式合併

簡略題意:現在有一棵二叉樹,所有非葉子節點都有兩個孩子。在每個葉子節點上有一個權值(有n個葉子節點,滿足這些權值為1..n的一個排列)。可以任意交換每個非葉子節點的左右孩子。要求進行一系列交換,使得最終所有葉子節點的權值按照遍歷序寫出來,逆序對個數最少。 考慮

CSU 1811 Tree Intersection(線段+啟發式合併 解法)

Problem Reference Meaning 一棵 n 個結點的樹,每個結點都有一種顏色,問對與樹上的每條邊,刪掉它之後得到的兩棵樹中,共有的顏色有多少種(在那兩棵樹中都有的顏色就是公有的顏色) Analysis 首先規定 1 號結點為整棵樹的根(其它號也可

BZOJ 3123 主席 啟發式合併

思路: 主席樹 搞樹上的k大 x+y-lca(x,y)-fa(lca(x,y)) 按照size小樹往大樹上插 啟發式合併 n*log^2n的 搞定~ //By SiriusRen #include <cstdio> #include &l

bzoj 3123: [Sdoi2013]森林 啟發式合併+可持久化線段

題意:給出一片森林,每個點有點權,要求資瓷兩個操作:詢問兩點間路徑的第k小點權;加一條邊 分析:如果沒有合併操作的話就是裸的可持久化線段樹啦。 但既然有合併操作那麼我們就每次把兩個塊的可持久化線段樹進行啟發式合併。 何為啟發式合併呢,其實就是暴力合併,把小一點的那棵樹上的

BZOJ 1012 線段||單調隊列

clu eof include urn str code ret max con 非常裸的線段樹 || 單調隊列: 假設一個節點在隊列中既沒有時間優勢(早點入隊)也沒有值優勢(值更大),那麽顯然不管在如何的情況下都不會被選為最大

BZOJ 1453 線段+並查集

題目連結:https://www.lydsy.com/JudgeOnline/problem.php?id=1453 題意:一個 n*n 的矩陣,每個位置有黑/白兩種顏色,有 m 次操作,每次可以翻轉其中一個位置的格子顏色,問每次操作後黑色和白色連通塊的個數。 題解:考慮若沒有翻轉顏色的操作時,可以用並查

HDU - 1540 Tunnel Warfare 線段區間合併與棧的結合

During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, vil

HDU - 4553 約會安排 線段 區間合併

 寒假來了,又到了小明和女神們約會的季節。    小明雖為屌絲級碼農,但非常活躍,女神們常常在小明網上的大段發言後熱情回覆“呵呵”,所以,小明的最愛就是和女神們約會。與此同時,也有很多基友找他開黑,由於數量實在過於巨大,怎麼安排時間便成了小明的一大心事。    我們已知小明一共有

HDU - 3911 Black And White 線段 區間合併

There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous ston

HDU - 3397 Sequence operation 線段 區間合併

lxhgww got a sequence contains n characters which are all '0's or '1's.  We have five operations here:  Change operations:  0 a b chang

森林[主席啟發式合併][樹上主席]

題目描述 小Z有一片森林,含有N個節點,每個節點上都有一個非負整數作為權值。初始的時候,森林中有M條邊。 小Z希望執行T個操作,操作有兩類: Q x y k查詢點x到點y路徑上所有的權值中,第k小的權值是多少。此操作保證點x和點y連通,同時這兩個節點的路徑上至少有k個點。 L

HDU1540 Tunnel Warfare 線段區間合併

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

HDU 3911 (線段,區間合併,延遲標記)

題意:就是給你一段由0和1組成的序列,然後有兩種操作:0 a b就是問從a到b最長的連續的1的長度為多少,1 a b就是把 [a,b]中的1變為0,0變為1。// 進行一次反轉操作,就是將區間0和1ji'l記錄的資料對換。 :用一個結構體,lmaxn1表示從最左邊數連續1的長度,lmaxn0表示

【ZOJ 4053】【青島網路賽主席+啟發式合併

題意:       給你一個數組,每次給你一個數,將這個數從整個陣列中刪去。然後陣列被劃分成了多個小區間,問你各個區間中最大的逆序對是多少。   思路:       首先建立一顆主席樹維護區間[1,x]的資訊。

HDU 1540(線段+區間合併)學習記錄

學習了線段樹的新姿勢,記錄一下 參考blog:https://blog.csdn.net/sunyutian1998/article/details/79618316 query的時候m-ql+1和qr-m寫成了m-l+1、r-m,wa了幾發之後才找到bug 錯誤樣例: 10 1Q 5 wrong

hihocoder-1116 : 計算 (線段區間合併

描述 現在有一個有n個元素的陣列a1, a2, ..., an。 記f(i, j) = ai * ai+1 * ... * aj。 初始時,a1 = a2 = ... = an = 0,每次我會

POJ 4718 /// 鏈剖分+線段區間合併 求樹上兩點間的LCIS長度

題目大意: 給定n個點 每個點都有權值 接下來給定樹的n條邊 第 i 個數 a[i] 表示 i+1到a[i]之間 有一條邊 給定q q個詢問 每次詢問給出 x y 求x到y的最長上升子序列的長度   題解 https://blog.csdn.net/forever_wjs/article/

HDU 5052 /// 鏈剖分+線段區間合併

題目大意: 給定n (表示樹有n個結點) 接下來n行給定n個點的點權(在這個點上買雞或者賣雞的價錢就是點權) 接下來n-1行每行給定 x y 表示x結點和y結點之間有一條邊 給定q (表示有q個詢問) 接下來q行 每行給定 x y v 查詢x到y的路徑上 先買雞再賣雞能夠贏得的最大利潤 買賣完後

Magician(hdu 5316 線段區間合併

題目連結: Magician   題意: 給定一個數組,定義beautiful subsequence為一個序列,裡面每個元素在給定陣列中的下標是奇偶交替的。 有2種操作: 0 求區間[a,b]中滿足beautiful subsequence的序列中,序列所有元

【BZOJ1483】[HNOI2009]夢幻布丁(平衡啟發式合併+並查集)

題目: BZOJ1483 分析: (這題碼了一下午,碼了近250行,但是意外跑的比本校各位神仙稍快,特寫部落格紀念) 首先能看出一個顯然的結論:顏色段數只會變少不會變多。 我們考慮用並查集維護區間,對於每個區間維護它的起點和終點。建\(n\)棵平衡樹,第\(i\)棵存顏色為\(i\)的區間。把\(x