【bzoj2441】 中山市选2011小W的问题 线段树

果然考试时候写题乱脑子,代码写的又臭又长。

首先五个点其实是找三个点V字形的,然后f[i]表示以i为结尾的V的个数,其实就是所有i左边纵坐标比i小的数中前面纵坐标比i大的数的个数,说起来好麻烦,意会即可。

第一眼感觉是树套树可做。

后来想了想,弃疗了。

先不考虑相等的情况。

果断想一想离线算法,按照纵坐标排序,从小到大插入数列中,每个点i维护一个data[i]表示未插入序列中横坐标小于i的数的个数,那么f[j]就等于1到j-1中所有已插入的data之和,为什么呢?因为现在在未插入数列中的数都是大于j的纵坐标的。然后每次插入j,就把j+1到n的所有data全部-1,注意赋初始值的时候的处理。

考虑上相等的情况果断炸了。

横坐标可以相等,纵坐标可以相等。

代码真心没法看。


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 100010
#define mod 1000000007

using namespace std;

struct yts
{
	int l,r,data,tag,len;
}t[4*maxn];

struct yts1
{
	int x,y,id,x1;
}p[maxn];

int n;
int f[maxn][2];

bool cmp(yts1 x,yts1 y)
{
	return x.x<y.x;
}

bool cmpp(yts1 x,yts1 y)
{
	return x.x>y.x;
}

bool cmp1(yts1 x,yts1 y)
{
	return x.id<y.id;
}

bool cmp2(yts1 x,yts1 y)
{
	return x.id>y.id;
}

bool cmp3(yts1 x,yts1 y)
{
	return x.y<y.y;
}

void update(int i)
{
	if (t[i].l==t[i].r) return;
	t[i].len=t[i*2].len+t[i*2+1].len;
	t[i].data=0;
	if (t[i*2].len) t[i].data=(t[i].data+t[i*2].data)%mod;
	if (t[i*2+1].len) t[i].data=(t[i].data+t[i*2+1].data)%mod;
}

void push(int i,int x)
{
	t[i].data=(t[i].data+t[i].len*x)%mod;
	t[i].tag=(t[i].tag+x)%mod;
}

void release(int i)
{
	if (t[i].l==t[i].r) return;
	if (!t[i].tag) return;
	push(i*2,t[i].tag);push(i*2+1,t[i].tag);
	t[i].tag=0;
}

void build(int i,int l,int r)
{
	t[i].l=l;t[i].r=r;
	t[i].tag=0;t[i].data=0;t[i].len=0;
	if (l==r) return;
	int mid=(l+r)/2;
	build(i*2,l,mid);build(i*2+1,mid+1,r);
}

void modify1(int i,int x,int d)
{
	if (t[i].l==t[i].r) {t[i].len=1;t[i].data=(t[i].tag+d)%mod;return;}
	release(i);
	int mid=(t[i].l+t[i].r)/2;
	if (x<=mid) modify1(i*2,x,d);
	else modify1(i*2+1,x,d);
	update(i);
}

void modify2(int i,int l,int r,int x)
{
	if (l>r) return;
	if (l<=t[i].l && t[i].r<=r) {push(i,x);return;}
	release(i);
	int mid=(t[i].l+t[i].r)/2;
	if (l<=mid) modify2(i*2,l,r,x);
	if (mid<r) modify2(i*2+1,l,r,x);
	update(i);
}

int query(int i,int l,int r)
{
	if (!t[i].len) return 0;
	if (l<=t[i].l && t[i].r<=r) return t[i].data;
	release(i);
	int mid=(t[i].l+t[i].r)/2;
	int ans=0;
	if (l<=mid) ans+=query(i*2,l,r);
	if (mid<r) ans+=query(i*2+1,l,r);
	return ans;
}

void solve0()
{
	sort(p+1,p+n+1,cmp3);
	build(1,1,n);
	for (int i=1;i<=n;i++)
	{
		int j=i;
		while (j<n && p[j+1].y==p[i].y) j++;
		for (int k=i;k<=j;k++) modify2(1,p[k].x1,n,-1);
		for (int k=i;k<=j;k++) f[p[k].id][0]=query(1,1,p[k].x-1);
		for (int k=i;k<=j;k++) modify1(1,p[k].id,p[k].x-1);
		i=j;
	}
}

void solve1()
{
	sort(p+1,p+n+1,cmp3);
	build(1,1,n);
	for (int i=1;i<=n;i++)
	{
		int j=i;
		while (j<n && p[j+1].y==p[i].y) j++;
		for (int k=i;k<=j;k++) modify2(1,1,p[k].x-1,-1);
		for (int k=i;k<=j;k++) f[p[k].id][1]=query(1,p[k].x1,n);
		for (int k=i;k<=j;k++) modify1(1,p[k].id,n-p[k].x1+1);
		i=j;
	}
}

int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
	sort(p+1,p+n+1,cmp);
	int mx=1;p[1].x1=1;
	for (int i=2;i<=n;i++)
	{
		if (p[i].x!=p[i-1].x) mx=i;
		p[i].x1=mx;
	}
	for (int i=1;i<=n;i++) p[i].x=p[i].x1;
	p[n].x1=n+1;
	for (int i=n-1;i>=1;i--)
	{
		if (p[i].x!=p[i+1].x) p[i].x1=p[i+1].x;
		else p[i].x1=p[i+1].x1;
	}
	for (int i=1;i<=n;i++) p[i].id=i;
	solve0();
	solve1();
	long long ans=0;
	for (int i=1;i<=n;i++)
	  ans=(ans+(long long)f[i][0]*f[i][1]%mod)%mod;
	printf("%lld\n",ans);
	return 0;
}


你可能感兴趣的:(【bzoj2441】 中山市选2011小W的问题 线段树)