因为是出题人所以题解就写复杂点
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 YiXi≤xi≤Yi且Bi≤yi≤CiBi \le yi \le CiBi≤yi≤Ci的果冻的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 43≤xi≤4且4≤yi≤54 \le yi \le 54≤yi≤5的果冻的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 15n≤15
对于另外 20%20\%20% 的数据,n≤104n \le 10^4n≤104且询问操作opropropr一定等于333
对于另外 20%20\%20% 的数据,n≤5×104n \le 5 \times 10^4n≤5×104且询问操作opropropr一定等于444
对于前 50%50\%50% 的数据,zi=1zi = 1zi=1
对于前 60%60\%60% 的数据,n≤105n \le 10^5n≤105,opr≤4opr \le 4opr≤4
对于前 95%95\%95% 的数据,n≤3×105n \le 3 \times 10^5n≤3×105,opr≤5opr \le 5opr≤5
对于前 100%100\%100% 的数据,n≤106n \le 10^6n≤106,opr≤5opr \le 5opr≤5,1≤xi,yi≤1051 \le xi, yi \le 10^51≤xi,yi≤105, 1≤zi≤1041 \le zi \le 10^41≤zi≤104,在所有操作中,询问的次数不超过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,但是他是正确的