1. 程式人生 > >bzoj2212 Tree Rotations

bzoj2212 Tree Rotations

hash class 交換 zoj || ostream spa ack lis

被BZOJ坑了一下午,原以為是我程序有問題一直WA,結果是我數組小了。。。為啥不給我RE!!!

線段樹合並,對於逆序對而言,只能通過交換左右子樹來達到,那麽我們就可以想到對於一個結點而言,我們當然要取左右子樹不叫換產生的逆序對,及交換產生的逆序對,取最小的就好了,另外呢,因為要維護子樹中包含的數,在往上遞歸時需要對該樹合並。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<string>
#include<set>
#include<algorithm>
#include
<vector> #include<queue> #include<list> #include<cmath> #include<cstring> #include<map> #include<stack> using namespace std; #define INF 0x3f3f3f3f #define maxn 2000005 #define ull unsigned long long #define ll long long #define hashmod 99999839 #define
mod 9997 int n,x,y; int ls[maxn],rs[maxn];//結點的左右兒子 int c[maxn],len;//結點代表的區間中有的個數 long long ans,s; stack<int> st; int newnode(){//返回一個新結點 int p; if(st.empty()) p = len++; else p = st.top(),st.pop(); ls[p] = rs[p] = 0,c[p] = 1; return p; } int bulid(int x){//建立葉子結點對應的樹並返回根
int root = newnode();//先申請一個新節點 int l = 1,r = n,mid,p = root; while(l < r){ mid = (l + r) >> 1; if(mid >= x) ls[p] = newnode(),p = ls[p],r = mid; else rs[p] = newnode(),p = rs[p],l = mid + 1; } return root; } int merge(int p,int q){//合並以p,q為根的樹,並返回新的根 if(!p || !q) return p + q; s += (long long)c[rs[p]] * c[ls[q]]; ls[p] = merge(ls[p],ls[q]); rs[p] = merge(rs[p],rs[q]); c[p] = c[ls[p]] + c[rs[p]]; st.push(q);//可將合並了的q結點放入st中 return p; } int solve(){ scanf("%d",&x); if(x) return bulid(x);//對葉節點建立一顆線段樹 int p = solve(),q = solve();//建立其左右兒子 ll t = c[p] * c[q]; s = 0,p = merge(p,q);//逆序對由非葉子結點產生 if(s <= t / 2) ans += s; else ans += t - s; return p; } void init(){ while(!st.empty()) st.pop(); len = 1,ans = 0; } int main(){ freopen("a.in","r",stdin); freopen("b.out","w",stdout); scanf("%d",&n); init(); solve(); printf("%lld",ans); return 0; }

bzoj2212 Tree Rotations