Codeforces Round #433 (Div. 1, based on Olympiad of Metropolises) C. Boredom(主席树)

题目链接:http://codeforces.com/contest/853/problem/C


查二维平面里有多少点,按行维护主席树,然后每次查一个区间,做差就可以求出二维平面里的点了,然后剩下的容斥一哈就行了,具体是把周围一圈剪掉,然后把四个角加上就好了,比较简单


代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=2e5+5;
const int M=MAXN*40;
int n,q,tot;
int a[MAXN];
int T[MAXN],lson[M],rson[M],c[M];
int build(int l,int r)
{
	int root=tot++;
	c[root]=0;
	if(l!=r)
	{
		int mid=(l+r)>>1;
		lson[root]=build(l,mid);
		rson[root]=build(mid+1,r);
	}
	return root;
}
int update(int root,int pos,int val)
{
	int newroot=tot++,tmp=newroot;
	c[newroot]=c[root]+val;
	int l=1,r=n;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(pos<=mid)
		{
			lson[newroot]=tot++;rson[newroot]=rson[root];
			newroot=lson[newroot];root=lson[root];
			r=mid;
		}
		else
		{
			rson[newroot]=tot++;lson[newroot]=lson[root];
			newroot=rson[newroot];root=rson[root];
			l=mid+1;
		}
		c[newroot]=c[root]+val;
	}
	return tmp;
}
int query(int root,int L,int R,int l,int r)
{
	if(L>R)
		return 0;
	if(L<=l&&r<=R)
		return c[root];
	int mid=(l+r)>>1;
	int ret=0;
	if(L<=mid)
		ret+=query(lson[root],L,R,l,mid);
	if(mid<R)
		ret+=query(rson[root],L,R,mid+1,r);
	return ret;
}
int Q(int l,int r,int L,int R)
{
	if(l>r)
		return 0;
	return query(T[r],L,R,1,n)-query(T[l-1],L,R,1,n);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	tot=0;
	scanf("%d%d",&n,&q);
	T[0]=build(1,n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;i++)
	{
		T[i]=update(T[i-1],a[i],1);
	}
	while(q--)
	{
		int l,r,d,u;
		ll cnt=0,ans=0;
		scanf("%d%d%d%d",&l,&r,&d,&u);
		cnt=Q(1,l-1,1,n);
		//printf("%d\n",cnt);
		ans-=cnt*(cnt-1)/2;

		cnt=Q(d+1,n,1,n);
		//printf("%d\n",cnt);
		ans-=cnt*(cnt-1)/2;
		
		cnt=Q(1,n,u+1,n);
		//printf("%d\n",cnt);
		ans-=cnt*(cnt-1)/2;
		
		cnt=Q(1,n,1,r-1);
		//printf("%d\n",cnt);
		ans-=cnt*(cnt-1)/2;
		
		cnt=Q(1,l-1,1,r-1);
		//printf("%d\n",cnt);
		ans+=cnt*(cnt-1)/2;
		
		cnt=Q(1,l-1,u+1,n);
		//printf("%d\n",cnt);
		ans+=cnt*(cnt-1)/2;
		
		cnt=Q(d+1,n,1,r-1);
		//printf("%d\n",cnt);
		ans+=cnt*(cnt-1)/2;
	
		cnt=Q(d+1,n,u+1,n);
		//printf("%d\n",cnt);
		ans+=cnt*(cnt-1)/2;
		//printf("%lld\n",ans);
		ans+=1LL*n*(n-1)/2;
		printf("%lld\n",ans);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值