3-20模拟赛【果冻之王】题解

本题解介绍了一道名为“果冻之王”的算法竞赛题目。题目要求通过一系列操作来管理和查询果冻集合,包括购买、食用及按条件求和等。提供了使用树状数组和CDQ分治的方法来解决此问题,实现复杂度为O(nlog^2n)。

因为是出题人所以题解就写复杂点

start_of_题面

果冻之王

时间限制:2s 空间限制:256M

题目描述

果冻是sekong_qi最喜爱的食物,每次模拟测试的评测结果出来后,sekong_qi都会前往小卖部买一大袋果冻。久而久之,sekong_qi开始变得对果冻非常了解,因此他对质量不好的果冻开始变得厌恶。为了辅助自己挑选合适的果冻,sekong_qi对不同的果冻进行了评估,并对每一个果冻设置了三个评估值xi,yi,zixi,yi,zixi,yi,zi。然而,sekong_qi发现自己光顾着对果冻进行了评估,忘记了对他们进行管理。因为sekong_qi还有享用自己的果冻,所以他决定将管理果冻的任务交给你。

输入描述

第一行一个正整数nnn,代表操作的数量。

接下来nnn行,每行先是一个正整数opropropr,代表操作的类型。

如果opr=1opr=1opr=1,接下来有三个数xi,yi,zixi, yi, zixi,yi,zi,代表sekong_qi又购买了一个三个评估值分别为xi,yi,zixi, yi, zixi,yi,zi的果冻。

如果opr=2opr=2opr=2,接下来没有输入,代表sekong_qi吃掉了目前拥有的果冻中最后一个购买的果冻。注意,有可能在吃掉上一个购买的果冻之前先进行了其他操作。

如果opr=3opr=3opr=3,接下来有一个正整数XiXiXi,代表sekong_qi向你询问目前他购买的所有果冻中满足xi>Xixi>Xixi>Xi的果冻的zizizi之和是多少。

如果opr=4opr=4opr=4,接下来有一个正整数YiYiYi,代表sekong_qi向你询问目前他购买的所有果冻中满足yi>Yiyi>Yiyi>Yi的果冻的zizizi之和是多少。

如果opr=5opr=5opr=5,接下来有四个正整数Xi,Yi,Bi,CiXi, Yi, Bi, CiXi,Yi,Bi,Ci,代表sekong_qi向你询问目前他购买的所有果冻中满足Xi≤xi≤YiXi \le xi \le YiXixiYiBi≤yi≤CiBi \le yi \le CiBiyiCi的果冻的zizizi之和是多少。

注意:由于sekong_qi的自制力并不高,有可能他刚刚买了一个果冻就会马上把它吃掉。

输出描述

对于每一个opr=3,4,5opr=3,4,5opr=3,4,5的询问,输出一行代表相应的结果。

输入样例1

6
1 3 5 7
1 2 7 9
3 1
3 2
4 5
5 3 4 4 6

输出样例1

16
7
9
7

样例1解释

首先,sekong_qi添加了评估值为(3,5,73, 5, 73,5,7)和(2,7,92, 7, 92,7,9)的两个果冻。

第三步,sekong_qi询问满足xi>1xi>1xi>1的果冻的zizizi之和,答案为7+9=167+9=167+9=16

第四步,sekong_qi询问满足xi>2xi>2xi>2的果冻的zizizi之和,只有第一个果冻满足条件,答案为777

第五步,sekong_qi询问满足yi>5yi>5yi>5的果冻的zizizi之和,只有第二个果冻满足条件,答案为999

第六步,sekong_qi询问满足3≤xi≤43 \le xi \le 43xi44≤yi≤54 \le yi \le 54yi5的果冻的zizizi之和,同样只有第一个果冻满足条件,答案为777

输入样例2

6
1 3 5 7
1 2 7 9
3 1
5 2 3 5 7
2
5 2 3 5 7

输出样例2

16
16
7

数据范围与约定

对于 10%10\%10% 的数据,n≤15n \le 15n15

对于另外 20%20\%20% 的数据,n≤104n \le 10^4n104且询问操作opropropr一定等于333

对于另外 20%20\%20% 的数据,n≤5×104n \le 5 \times 10^4n5×104且询问操作opropropr一定等于444

对于前 50%50\%50% 的数据,zi=1zi = 1zi=1

对于前 60%60\%60% 的数据,n≤105n \le 10^5n105opr≤4opr \le 4opr4

对于前 95%95\%95% 的数据,n≤3×105n \le 3 \times 10^5n3×105opr≤5opr \le 5opr5

对于前 100%100\%100% 的数据,n≤106n \le 10^6n106opr≤5opr \le 5opr51≤xi,yi≤1051 \le xi, yi \le 10^51xi,yi105, 1≤zi≤1041 \le zi \le 10^41zi104,在所有操作中,询问的次数不超过2×1052 \times 10^52×105

数据保证任何时刻sekong_qi的果冻都不超过10510^5105

end_of_题面

首先读懂题的人能够获得10分

如果你会树状数组,你可以以权值为树状数组进行插入和查询
或者如果你会平衡树,你可以写一个treap维护插入和查询前驱
针对xixixi值或yiyiyi值你可以获得50分,将两者结合你可以获得60分

所以其实这题送了60分

如果你会树套树的话,那么非常好,你可以无脑上树套树获得至少95分,如果你常数小一点可以直接AC,当然前提是你写对。(事实上我本来可以卡空间,但是因为出题有些急没有想到)。当然,如果评测机慢一点的话你可能会一直95,比如题面中的sekong_qi的树套树就因为某种常数原因一直95,前两天才卡过。

如果你写过cdq分治,那么你会发现其实这道题就是一个裸的二维偏序,你可以把三种询问都拆成平面上的点然后在矩形内查询,树状数组维护,复杂度O(nlog2n)O(nlog^2n)O(nlog2n)虽然复杂度和树套树一样,但常数很小,在我们的渣评测机上依然跑得比某地reporter还快

start_of_std

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int X = 100000 + 1000;
const int N = 600000 + 1000;

int t[X], ans[N], fc, n;
int tot = 0, aid = 0, asum = 0, stkx[N], stky[N], stkz[N], xi, yi, zi, ci;
int top = 0, lc;
struct Opreation{
	int x, y, opr, id, qid, f;
}a[N << 2], temp[N << 2];

inline int read()
{
	int a = 0;
	bool flag = false;
	char ch;
	while(!((((ch = getchar()) >= '0') && (ch <= '9')) || (ch == '-')));
	if(ch == '-')
		flag = true;
	else
	{
		a = a * 10;
		a += ch - '0';
	}
	while((((ch = getchar()) >= '0') && (ch <= '9')) || (ch == '-'))
	{
		a = a * 10;
		a += ch - '0';
	}
	if(flag)
		a = -a;
	return a;
}

inline int lowbit(int x)
{
	return x & -x;
}

inline bool cmp(Opreation A, Opreation B)
{
	if(A.x != B.x)
		return A.x < B.x;
	else if(A.y != B.y)
		return A.y < B.y;
	else
		return A.opr < B.opr;
}

inline void add(int x, int c)
{
	for(;x <= 100000;x += lowbit(x))
		t[x] += c;
}

inline int query(int x)
{
	int ret = 0;
	for(;x > 0;x -= lowbit(x))
		ret += t[x];
	return ret;
}

inline void Add(int A, int B, int C, int D, int E, int F, int G)
{
	a[A].opr = F;
	a[A].x = B;
	a[A].y = C;
	a[A].f = D;
	a[A].qid = E;
	a[A].id = G;
}

inline void cdq(int l, int r)
{
	if(l == r)
		return;
	int mid = (l + r) >> 1;
	for(int i = l;i <= r;++i)
	{
		if(a[i].opr == 1 && a[i].id <= mid)
			add(a[i].y, a[i].f);
		else if(a[i].opr == 2 && a[i].id > mid)
			ans[a[i].qid] += a[i].f * query(a[i].y);
	}
	for(int i = l;i <= r;++i)  
        if(a[i].opr == 1 && a[i].id <= mid)
        	add(a[i].y, -a[i].f);
    int h1 = l, h2 = mid;
    for(int i = l; i <= r; i++)  
        if(a[i].id <= mid)
        	temp[h1++] = a[i];
        else
        	temp[++h2] = a[i];
    for(int i = l;i <= r;++i)
    	a[i] = temp[i];
    cdq(l, mid);
    cdq(mid + 1, r);
}

int main()
{
	n = read();
	for(int i = 1;i <= n;++i)
	{
		fc = read();
		if(fc == 1)
		{
			xi = read(), yi = read(), zi = read();
			++tot;
			Add(tot, xi, yi, zi, 0, 1, tot);
			stkx[++top] = xi, stky[top] = yi, stkz[top] = zi;
			asum += zi;
			lc = fc;
		}
		if(fc == 2)
		{
			asum -= stkz[top];
			if(lc == 1)
				--tot;
			else
				++tot, Add(tot, stkx[top], stky[top], -stkz[top], 0, 1, tot);
			--top;
		}
		else if(fc == 3)
		{
			++aid;
			ans[aid] += asum;
			xi = read();
			++tot;
			Add(tot, xi, 100000, -1, aid, 2, tot);
		}
		else if(fc == 4)
		{
			++aid;
			ans[aid] += asum;
			yi = read();
			++tot;
			Add(tot, 100000, yi, -1, aid, 2, tot);
		}
		else if(fc == 5)
		{
			++aid;
			xi = read(), zi = read(), yi = read(), ci = read();
			++tot;
			Add(tot, zi, ci, 1, aid, 2, tot);
			++tot;
			Add(tot, zi, yi - 1, -1, aid, 2, tot);
			++tot;
			Add(tot, xi - 1, ci, -1, aid, 2, tot);
			++tot;
			Add(tot, xi - 1, yi - 1, 1, aid, 2, tot);
		}
		lc = fc;
	}
	sort(a + 1, a + 1 + tot, cmp);
	cdq(1, tot);
	for(int i = 1;i <= aid;++i)
		printf("%d\n", ans[i]);
	return 0;
}

end_of_std

PS:树套树题解可以看http://www.cnblogs.com/SirKnight/p/8666794.html ,虽然这个人因为我们的渣评测机原因依然是95,但是他是正确的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值