cdq分治bzoj3295

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n, m;
long long bit[200000],pos[200000],num[200000];
struct node
{
	int x, y, t;
};
void add(int num, int pos)
{
	int temp = pos;
	while (temp<=n)
	{
		bit[temp] += num; temp += (temp&(-temp));
	}
}
long long sum(int pos)
{
	long long sum = 0;
	while (pos)
	{
		sum += bit[pos];
		pos -= (pos&(-pos));
	}
	return sum;
}
node tree[200000],temptree[200000];
void cdq(int l, int r)//cdq分治就是从顶朝下然后符合要求的树进树状数组,然后查询,然后用完了出数组。
{
	if (l >= r)return;
	int mid = (l + r) / 2;
	int l1=l, l2=mid+1;
	for (int i = l; i <= r; i++)
		if (tree[i].t <= mid)
			temptree[l1++] = tree[i];
		else
			temptree[l2++] = tree[i]; 
	for (int i = l; i <= r; i++)
	{
		tree[i] = temptree[i];
	}
	int last = l;
	for (int i = mid + 1; i < l2; i++)
	{
		while (tree[last].x < tree[i].x&&last<l1)
			add(1, tree[last].y),last++;
		long long all = sum(tree[i].y);
		num[tree[i].t] +=(long long) (last - l - all);
	}
        last = l;
	for (int i = mid + 1; i < l2; i++)
	{
		while (tree[last].x < tree[i].x&&last<l1)
			add(-1, tree[last].y), last++;
	}
	 last = mid;
	for (int i = l2-1; i >= mid+1; i--)
	{
		while (tree[last].x > tree[i].x&&last>=l)
			add(1, tree[last].y), last--;
		long long all = sum(tree[i].y);
		num[tree[i].t] += all;
	}
	last = mid;
	for (int i = l2 - 1; i >= mid + 1; i--)
	{
		while (tree[last].x > tree[i].x&&last >= l)
			add(-1, tree[last].y), last--;
	}
	cdq(l, mid); cdq(mid + 1, r);
}
int main()
{
	//n = 10;
	//add(1, 2);
	//add(1, 3);
	///add(2, 9);
	//cout << sum(10) << endl;
	scanf("%d%d", &n, &m);
	//n = 100000; m = 1;
	int tempn = n;
        for (int i = 1; i <= n; i++)
	{
		scanf("%d", &tree[i].y); pos[tree[i].y] = i; tree[i].x = i;
	}
	//for (int i = 1,k=n; i<=n; i++,k--)
	//{
	//	tree[i].y = k; tree[i].x = i; pos[tree[i].y] = i;
	//}
	for (int i = m; i >=1; i--)
	{
		int temp;
		scanf("%d", &temp);
		tree[pos[temp]].t = tempn--;
	}
	for (int i = 1; i <= n; i++)if (tree[i].t == 0)tree[i].t = tempn--;
	cdq(1, n);
	for (int i = 2; i<=n; i++)
		num[i] += num[i - 1];
	for (int i = 1,k=n; i<=m; i++,k--)
	{
		//cout << "i:" << i << endl;
		printf("%lld\n", num[k]);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值