三校联考20181024T3 统计count

题意:
题面
子任务

题解:
话说T2和T3的位置是故意的吧?还有std的代码真丑(就像隔壁苏珊婶婶做的苹果派一样)(基本上全机房的人都这么想)。
先说60%的数据,直接暴力枚举要取出的位置,暴力排序,然后每一次用树状数组或归并排序求逆序对数即可。
对于100%的数据,我们可以维护一个 f [ i ] f[i] f[i] j &gt; i , a [ j ] &lt; a [ i ] j&gt;i,a[j]&lt;a[i] j>i,a[j]<a[i] j j j的个数,那么逆序对数就是 ∑ f [ i ] \sum f[i] f[i]。可以发现,经过一次操作后,被安排的位置的 f [ i ] f[i] f[i]就变成了0,而其他位置不变。因为如果一个位置被安排了,那么它前面的数后面还是那些数,后面的比它小的位置也会被安排,而比它大的位置不变,而且被安排到它后面的仍然比它小。因为f[i]变成0之后就对答案没有贡献了,所以我们就不用再维护被安排过的位置了。
用线段树维护一下一个区间中f[i]的和与a[i]的最小值,操作时,如果区间的最小值 ≤ a j k \le a_{j_k} ajk,就递归下去直到叶节点。如果某个位置被安排了,就把这个位置上的f[i]变为0,最小值变为INF。

代码:

#include<cstdio>
#include<algorithm>
#define maxn 200005
#define INF (LL)1e16
#define LL long long
using namespace std;
int n,m,a[maxn],tmp[maxn],bit[maxn],f[maxn],cnt;
inline int lowbit(int x) { return x&(-x); }
void Add(int x,int d) { for(;x<=n;x+=lowbit(x)) bit[x]+=d; }
int Query(int x)
{
	int res=0;
	for(;x;x-=lowbit(x)) res+=bit[x];
	return res;
}
struct node { LL f,minx; } tree[maxn*4];
void Pushup(int i) { tree[i].f=tree[i<<1].f+tree[i<<1|1].f,tree[i].minx=min(tree[i<<1].minx,tree[i<<1|1].minx); }
void Build(int i,int l,int r)
{
	if(l==r) { tree[i].f=f[l],tree[i].minx=a[l]; return; }
	int mid=(l+r)>>1;
	Build(i<<1,l,mid); Build(i<<1|1,mid+1,r);
	Pushup(i);
}
void Modify(int i,int l,int r,int p,int d)
{
	if(tree[i].minx>d) return;
	if(l==r) { tree[i].minx=INF,tree[i].f=0; return; }
	int mid=(l+r)>>1;
	if(p<=mid) Modify(i<<1,l,mid,p,d);
	Modify(i<<1|1,mid+1,r,p,d);
	Pushup(i);
}
bool Query(int i,int l,int r,int p)
{
	if(l==r) return tree[i].f!=0;
	int mid=(l+r)>>1;
	if(p<=mid) return Query(i<<1,l,mid,p);
	else return Query(i<<1|1,mid+1,r,p);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=n;i;i--)
	{
		f[i]=Query(a[i]-1);
		Add(a[i],1);
	}
	Build(1,1,n);
	printf("%lld",tree[1].f);
	while(m--)
	{
		int jk;
		scanf("%d",&jk);
		if(Query(1,1,n,jk)) Modify(1,1,n,jk,a[jk]);
		printf(" %lld",tree[1].f);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值