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

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

直接遍历就可以了

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值