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