洛谷 P3521 [POI2011]ROT-Tree Rotations 解題報告
阿新 • • 發佈:2018-07-30
方式 遞歸 sum 合並 += line 相關 ota 報告
的
P3521 [POI2011]ROT-Tree Rotations
題意:遞歸給出給一棵\(n(1≤n≤200000)\)個葉子的二叉樹,可以交換每個點的左右子樹,要求前序遍歷葉子的逆序對最少。
大體給出方式:
第一行一個正整數\(n\),表示該二叉樹的葉節點的個數;
下面若幹行,每行一個數\(p\):
如果\(p=0\),表示這個節點不是葉節點,遞歸地向下讀入其左孩子和右孩子的信息;
如果\(p \neq 0\) ,表示這個節點是葉節點,權值為\(p\) 。
本來想學一下啟發式合並的,結果被一個很神奇的錯誤卡了很久。。
啟發式合並的復雜度沒怎麽學會,只是大致知道權值線段樹的合並和相同的節點數量成正相關,反正把只有一條鏈的權值線段樹都合起來的復雜度是\(O(nlogn)\)
不過在最後出現了一個神奇的錯誤
10分:
int dfs()
{
scanf("%d",&k);
if(k) return build(1,n,k);
s1=s2=0;
int now=Merge(dfs(),dfs());
ans+=min(s1,s2);
return now;
}
100分:
int dfs() { scanf("%d",&k); if(k) return build(1,n,k); int now=Merge(dfs(),dfs()); ans+=min(s1,s2); s1=s2=0; return now; }
註意遞歸時賦初值該在什麽時候搞
Code:
#include <cstdio> #define ll long long #define ls ch[now][0] #define rs ch[now][1] const int N=200000; ll min(ll x,ll y){return x<y?x:y;} int ch[N*25][2],n,k,tot; ll sum[N*25],ans,s1,s2; int build(int l,int r,int pos) { int now=++tot; sum[now]++; if(l==r) return now; int mid=l+r>>1; if(pos<=mid) ls=build(l,mid,pos); else rs=build(mid+1,r,pos); return now; } int Merge(int x,int y) { if(!x||!y) return x+y; sum[x]+=sum[y]; s1+=sum[ch[x][1]]*sum[ch[y][0]]; s2+=sum[ch[x][0]]*sum[ch[y][1]]; ch[x][0]=Merge(ch[x][0],ch[y][0]); ch[x][1]=Merge(ch[x][1],ch[y][1]); return x; } int dfs() { scanf("%d",&k); if(k) return build(1,n,k); int now=Merge(dfs(),dfs()); ans+=min(s1,s2); s1=s2=0; return now; } int main() { scanf("%d",&n); dfs(); printf("%lld\n",ans); return 0; }
2018.7.30
洛谷 P3521 [POI2011]ROT-Tree Rotations 解題報告