XJOI-NOIP2015提高组模拟题1 day1

其实这只是一道题的题解= =;

博主太弱不会T1T3;

然而我还是要吐槽一下,T2难道你们就没有一点写数据结构的心情吗!


T1:

留坑(不太可能填);


T2:

题意:

给出大小为n的一个四维点集,和m次询问;

每次询问给出一个点,求四维坐标均小于等于这个点的集合大小;

n,m<=30000;

题解:

看到这题的第一反应是排序乱搞,noip难度应该随便玩玩就过了嘛(笑);

但是仔细看看不是这么回事!

bzoj有一道题叫陌上花开——然而那个是三维的;

回忆一下,PoPoQQQ让我们搞排序+CDQ分治+树状数组;

hzwer让我们搞排序+树状数组套平衡树;

反正都是降维,综合一下,就是排序+CDQ分治+树状数组套平衡树不就搞出来了!

码!

具体搞法和一般的CDQ分治差不多,只是插入查询树状数组改成了树状数组套平衡树;

每次插入查询都是时间是O(log^2n)的,总体算上CDQ分治;

时间复杂度O(nlog^3n),空间复杂度O(nlogn);

这个效率还是不错的,但是正解并不是这个;

正解是用bitset来维护集合的交;

每次关于一维排序,求每个询问在这一维上小于等于的点集,用一个bitset记录;

然后将这些bitset与(&)起来,得到的集合就是最后的点集;

复杂度O(4*n^2/32),效率比上面的高级数据结构快一些,并且极为好写;

正解的做法还可以再向高维拓展,而高级数据结构就很难继续了;

(正解代码懒得写了,大家理解一下应该都是可以yy的(笑));

//更新:bitset正解的代码见下面;



代码:


排序+CDQ分治+树状数组套平衡树:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 31000
#define lson tr[tr[x].l]
#define rson tr[tr[x].r]
using namespace std;
struct node
{
	double a, b, c, d;
	int num_ans, no;
}t[N << 1], temp[N << 1];
struct treap
{
	double val;
	int size, rnd, l, r;
	void clear()
	{
		size = 1, rnd = rand(), l = 0, r = 0;
	}
}tr[N * 20];
double dis[N << 1];
int len, cnt, ans[N];
int root[N << 1];
bool cmp1(node a, node b)
{
	if (a.a == b.a)
		return a.num_ans<b.num_ans;
	return a.a < b.a;
}
bool cmp2(node a, node b)
{
	return a.b < b.b;
}
int lowbit(int x)
{
	return x&(-x);
}
void Pushup(int x)
{
	tr[x].size = lson.size + rson.size + 1;
}
void lturn(int &x)
{
	int t = tr[x].r;
	tr[x].r = tr[t].l;
	tr[t].l = x;
	tr[t].size = tr[x].size;
	Pushup(x);
	x = t;
}
void rturn(int &x)
{
	int t = tr[x].l;
	tr[x].l = tr[t].r;
	tr[t].r = x;
	tr[t].size = tr[x].size;
	Pushup(x);
	x = t;
}
void Insert(int &x, double val)
{
	if (!x)
	{
		tr[x = ++cnt].clear();
		tr[x].val = val;
		return;
	}
	tr[x].size++;
	if (val <= tr[x].val)
	{
		Insert(tr[x].l, val);
		if (tr[x].rnd < lson.rnd)
			rturn(x);
	}
	else
	{
		Insert(tr[x].r, val);
		if (tr[x].rnd > rson.rnd)
			lturn(x);
	}
}
int query(int x, double val)
{
	if (!x)	return 0;
	if (tr[x].val > val)
		return query(tr[x].l, val);
	else
		return lson.size + 1 + query(tr[x].r, val);
}
void add(int k, double val)
{
	while (k <= len)
	{
		Insert(root[k], val);
		k += lowbit(k);
	}
}
void clear(int k)
{
	while (k <= len && root[k])
	{
		root[k] = 0;
		k += lowbit(k);
	}
}
int getans(int k, double val)
{
	int ret = 0;
	while (k)
	{
		ret += query(root[k], val);
		k -= lowbit(k);
	}
	return ret;
}
void divide(int l, int r)
{
	int mid = l + r >> 1;
	memcpy(temp + l, t + l, sizeof(node)*(r - l + 1));
	for (int i = l, j = l, k = mid + 1; i <= r; i++)
	{
		if (temp[i].no <= mid)
			t[j++] = temp[i];
		else
			t[k++] = temp[i];
	}
}
void merge(int l, int r)
{
	int mid = l + r >> 1;
	memcpy(temp + l, t + l, sizeof(node)*(r - l + 1));
	for (int i = l, j = l, k = mid + 1; i <= r; i++)
	{
		if (j <= mid&&k <= r)
			t[i] = temp[j].b < temp[k].b ? temp[j++] : temp[k++];
		else
			t[i] = (j == mid + 1 ? temp[k++] : temp[j++]);
	}
}
void slove(int l, int r)
{
	if (l == r)		return;
	divide(l, r);
	int mid = l + r >> 1, i, j;
	slove(l, mid);
	for (i = mid + 1, j = l, cnt = 0; i <= r; i++)
	{
		while (j <= mid&&t[j].b <= t[i].b)
		{
			if (!t[j].num_ans)
			{
				add(lower_bound(dis + 1, dis + len + 1, t[j].c) - dis, t[j].d);
			}
			j++;
		}
		if (t[i].num_ans)
		{
			ans[t[i].num_ans] += getans(lower_bound(dis + 1, dis + len + 1, t[i].c) - dis, t[i].d);
		}
	}
	while (j >= l)
	{
		if (!t[j].num_ans)
		{
			clear(lower_bound(dis + 1, dis + len + 1, t[j].c) - dis);
		}
		j--;
	}
	slove(mid + 1, r);
	merge(l, r);
}
int main()
{
	int n, m, i, j, k;
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	{
		scanf("%lf%lf%lf%lf", &t[i].a, &t[i].b, &t[i].c, &t[i].d);
	}
	scanf("%d", &m);
	for (i = 1; i <= m; i++)
	{
		scanf("%lf%lf%lf%lf", &t[i + n].a, &t[i + n].b, &t[i + n].c, &t[i + n].d);
		t[i + n].num_ans = i;
		dis[i + n] = t[i + n].c;
	}
	sort(dis + 1, dis + n + m + 1);
	len = unique(dis + 1, dis + n + m + 1) - dis - 1;
	sort(t + 1, t + n + m + 1, cmp1);
	for (i = 1; i <= n + m; i++)
	{
		t[i].no = i;
	}
	sort(t + 1, t + n + m + 1, cmp2);
	slove(1, n + m);
	for (i = 1; i <= m; i++)
	{
		printf("%d\n", ans[i]);
	}
	return 0;
}


正解bitset:

#include<bitset>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 31
using namespace std;
struct Point
{
	double x[4];
	int no;
	void read()
	{
		scanf("%lf%lf%lf%lf",x,x+1,x+2,x+3);
	}
}a[N],b[N];
int C;
bitset<N>temp,ans[N];
bool cmp(Point a,Point b)
{
	return a.x[C]<b.x[C];
}
int main()
{
	int n,m,i,j,k;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		a[i].read(),a[i].no=i;
	scanf("%d",&m);
	for(i=1;i<=m;i++)
		b[i].read(),b[i].no=i;
	for(C=0;C<4;C++)
	{
		sort(a+1,a+n+1,cmp);
		sort(b+1,b+m+1,cmp);
		temp=0,i=1;
		for(j=1;j<=m;j++)
		{
			while(i<=n&&a[i].x[C]<=b[j].x[C])
				temp[a[i++].no]=1;
			if(!C)
				ans[b[j].no]=temp;
			else
				ans[b[j].no]&=temp;
		}
	}
	for(i=1;i<=m;i++)
		printf("%d\n",ans[i].count());
	return 0;
}




T3:

我选择弃疗,计算几何目前还是弱鸡,等学了半平面交有心情再搞搞(?)吧



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值