bzoj2212 Tree Rotations

被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;
}

 

posted @ 2018-08-26 17:03  zhuiyicc  阅读(134)  评论(0编辑  收藏  举报