zoukankan      html  css  js  c++  java
  • bzoj2212[Poi2011]Tree Rotations [线段树合并]

    题面

    bzoj

    ans = 两子树ans + min(左子在前逆序对数, 右子在前逆序对数)
    线段树合并

    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #define Sqr(x) ((x)*(x))
    using namespace std;
    const int N = 2e5 + 5;
    const int M = 4e6 + 5;
    long long cnt1, cnt2;
    struct Seg{
    	int w[M], sz, ls[M], rs[M];
        void ins(int l, int r, int x, int &rt){
    		if(!rt) rt = ++sz;
    		if(l == r) {w[rt] = 1; return ;}
    		int mid = l + ((r - l) >> 1);
    		if(x <= mid) ins(l, mid, x, ls[rt]); 
    		else ins(mid + 1, r, x, rs[rt]);
    		w[rt] = w[ls[rt]] + w[rs[rt]];
    	}
    	int merge(int x, int y){
    		if(!x || !y) return x + y;
    		cnt1 += 1ll * w[ls[x]] * w[rs[y]];
    		cnt2 += 1ll * w[rs[x]] * w[ls[y]];
    		ls[x] = merge(ls[x], ls[y]);
    		rs[x] = merge(rs[x], rs[y]);
    		w[x] = w[ls[x]] + w[rs[x]];
    		return x;
    	}
    }seg;
    int n, m, sz, rt[N << 2], l[N << 2], r[N << 2], w[N << 2];
    
    void init(int &cur){
    	cur = ++sz;
    	scanf("%d", &w[cur]);
    	if(!w[cur]) {init(l[cur]); init(r[cur]);}
    	else seg.ins(1, n, w[cur], rt[cur]);
    }
    
    long long solve(int cur){
        if(w[cur]) return 0;//如果不在叶子节点停下 叶子就会被合并成空树 
    	long long res = solve(l[cur]) + solve(r[cur]);
    	//printf("%d %lld %d %d
    ", cur, res, l[cur], r[cur]);
        cnt1 = cnt2 = 0;
        rt[cur] = seg.merge(rt[l[cur]], rt[r[cur]]);
        //printf("%lld %lld
    ", cnt1, cnt2);
        return res + min(cnt1, cnt2);
    }
    
    int main() {
    	scanf("%d", &n);
    	init(m);
    	printf("%lld
    ", solve(m));
    	//system("PAUSE");
        return 0;
    }
    /*
    检查所有的int函数是否有返回值 
    */
    
  • 相关阅读:
    Prism-超轻量的开源框架
    1的数目
    二叉树中和为某一值得路径
    把二叉树打印成多行
    对称的二叉树
    二叉树的下一个节点
    删除链表中重复的结点
    数组中的重复数字
    连表中环入口的节点
    把字符串换成整数
  • 原文地址:https://www.cnblogs.com/hjmmm/p/10654632.html
Copyright © 2011-2022 走看看