【FZU】2184 逆序数还原(线段树)

来源:互联网 发布:淘宝上门取件在哪里 编辑:程序博客网 时间:2024/05/22 07:40

题目思路:这道题目其实跟插队那题线段树是一样的。

直接遍历就可以了

 #include<iostream>  #include<algorithm>  #include<cstdio>  #include<cstring>  using namespace std;#define MAX 200005  #define ls rt<<1  #define rs ls|1  #define m ((l+r)>>1)  int sum[MAX << 2][3];int col[MAX << 2];int posx[MAX];int n, k;struct node{int l, r, h, s;node(){}node(int _l, int _r, int _h, int _s){l = _l;r = _r;h = _h;s = _s;}bool operator<(node b)const{return h < b.h;}}p[MAX];void uprt(int l, int r, int rt){memset(sum[rt], 0, sizeof(sum[rt]));if (col[rt] >= k){sum[rt][k] = posx[r + 1] - posx[l];return;}if (l == r){sum[rt][col[rt]] = posx[r + 1] - posx[l];}else{int cur = col[rt];for (int i = col[rt]; i < k; i++)sum[rt][i] = sum[ls][i - cur] + sum[rs][i - cur];for (int i = k - cur; i <= k; i++)sum[rt][k] += sum[ls][i] + sum[rs][i];}}void updata(int L, int R, int c, int l, int r, int rt){if (L <= l&&r <= R){col[rt] += c;uprt(l, r, rt);return;}int mid = m;if (L <= mid)updata(L, R, c, l, mid, ls);if (mid < R)updata(L, R, c, mid + 1, r, rs);uprt(l, r, rt);}void build(int l, int r, int rt){col[rt] = 0;sum[rt][0] = posx[r + 1] - posx[l];//0次的时候默认是这样子。为了k>1的时候,需要传递  if (l == r)return;build(l, m, ls);build(m + 1, r, rs);}int main(){int t;cin >> t;int icase = 1;while (t--){scanf("%d", &n);k = 2;memset(col, 0, sizeof(col));memset(sum, 0, sizeof(sum));int x1, x2, y1, y2;int cnt = 0;for (int i = 0; i < n; i++){scanf("%d%d%d%d", &x1, &y1, &x2, &y2);p[cnt] = node(x1, x2, y1, 1);posx[cnt++] = x1;p[cnt] = node(x1, x2, y2, -1);posx[cnt++] = x2;}sort(posx, posx + cnt);sort(p, p + cnt);int cnt2 = unique(posx, posx + cnt) - posx;long long ans = 0;build(0, cnt2 - 1, 1);for (int i = 0; i < cnt - 1; i++){int curl = lower_bound(posx, posx + cnt2, p[i].l) - posx;int curr = lower_bound(posx, posx + cnt2, p[i].r) - posx - 1;if (curl <= curr)updata(curl, curr, p[i].s, 0, cnt2 - 1, 1);ans += (long long)(sum[1][1]) * (p[i + 1].h - p[i].h);}printf("Case %d: %lld\n", icase++, ans);}}


0 0
原创粉丝点击