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
#include
#include
#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 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
#include
#include
#include
#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;
bitsettemp,ans[N];
bool cmp(Point a,Point b)
{
	return a.x[C]




T3:

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



你可能感兴趣的:(其他题型,数据结构,其他OJ,OIer刷题记录)