题目链接
题目中有这样的三种操作:
- 清空
- 添加颜色进(x,y)这个点颜色c
- 查询(1,y1)到(x,y2)区间内有几种颜色
一开始的时候我直接写了个二维主席树,但是就是RE过不去,但是开大点就会TLE了,所以实在没法,只能想别的办法来做。
这里的突破口还是在这个“1”上面,我们其实可以看作是查询一个前缀和的形式,但是限制条件y的范围在[y1, y2]之间。
所以,我的做法就是用CDQ分治来处理时间和x轴前缀和上这样一个问题,然后呢,我们可以开一个线段树来维护对应时间戳上我们处理到的y轴上的信息,因为保证了x的升序,所以保证了在区间内的y一定是会被包含在里面的。
那么,我们对应上时间戳,岂不就可以推到CDQ分治上去了嘛。
但是,有个问题,就是在这里的“0”(清空),应该怎么办呢,我们可以将它考虑成为多组输入,上面已经输入的,我们直接进行操作,然后对于下面的我们再进行分开考虑,所以最后结束的时候也不要忘记再处理一遍。
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 3e5 + 7;
int tot;
ull ans[maxN] = {0};
bool lazy[maxN << 2] = {false};
ull tree[maxN << 2] = {0};
int Lsan_Y[400017], cnt_y, _Ux, _Uy, need_out, re_tim[150017];
struct Question
{
int op, x, y, c, tim;
Question(int a=0, int b=0, int cc=0, int d=0, int f=0):op(a), x(b), y(cc), c(d), tim(f) {}
}qes[150017], cop[150017];
inline void pushup(int rt) { tree[rt] = tree[lsn] | tree[rsn]; }
inline void pushdown(int rt)
{
if(lazy[rt])
{
tree[lsn] = tree[rsn] = 0;
lazy[lsn] = lazy[rsn] = true;
lazy[rt] = false;
}
}
inline void update(int rt, int l, int r, int qx, int col)
{
if(l == r)
{
tree[rt] |= (ull)1 << (ull)col;
return;
}
pushdown(rt);
int mid = HalF;
if(qx <= mid) update(Lson, qx, col);
else update(Rson, qx, col);
pushup(rt);
}
inline ull query(int rt, int l, int r, int ql, int qr)
{
if(ql <= l && qr >= r) return tree[rt];
pushdown(rt);
int mid = HalF;
if(qr <= mid) return query(QL);
else if(ql > mid) return query(QR);
else return query(QL) | query(QR);
}
inline int Count_num(ull val)
{
int cnt_num = 0;
while(val)
{
cnt_num += val & (ull)1;
val >>= (ull)1;
}
return cnt_num;
}
void CDQ(int l, int r)
{
if(l == r) return;
int ql = l, mid = (l + r) >> 1, qr = mid + 1; //mid = time_num
for(int i=l; i<=r; i++)
{
if(qes[i].tim <= mid)
{
cop[ql++] = qes[i];
if(qes[i].op == 1)
{
update(1, 1, _Uy, qes[i].y, qes[i].c);
}
}
else
{
cop[qr++] = qes[i];
if(qes[i].op == 2)
{
ans[qes[i].tim] |= query(1, 1, _Uy, qes[i].y, qes[i].c);
}
}
}
lazy[1] = true;
for(int i=l; i<=r; i++) qes[i] = cop[i];
CDQ(l, mid); CDQ(mid + 1, r);
}
inline bool cmp_x(Question e1, Question e2) { return e1.x == e2.x ? e1.op < e2.op : e1.x < e2.x; }
int Q;
inline void solve()
{
sort(Lsan_Y + 1, Lsan_Y + cnt_y + 1);
_Uy = (int)(unique(Lsan_Y + 1, Lsan_Y + cnt_y + 1) - Lsan_Y - 1);
for(int i=1; i<=Q; i++)
{
qes[i].y = (int)(lower_bound(Lsan_Y + 1, Lsan_Y + _Uy + 1, qes[i].y) - Lsan_Y);
if(qes[i].op == 2) qes[i].c = (int)(lower_bound(Lsan_Y + 1, Lsan_Y + _Uy + 1, qes[i].c) - Lsan_Y);
}
sort(qes + 1, qes + Q + 1, cmp_x);
if(Q) CDQ(1, Q);
for(int i=1; i<=need_out; i++) printf("%d\n", Count_num(ans[re_tim[i]]));
}
int main()
{
int op; tot = 0; cnt_y = need_out = Q = 0; tree[0] = 0; lazy[1] = true;
int x, y, c, y1, y2;
while(scanf("%d", &op) && (op ^ 3))
{
if(!op) //clear
{
solve();
Q = 0;
cnt_y = need_out = 0;
}
else if(op == 1) //add
{
++Q; ans[Q] = 0;
scanf("%d%d%d", &x, &y, &c);
qes[Q] = Question(op, x, y, c, Q);
Lsan_Y[++cnt_y] = y;
}
else //query
{
++Q; ans[Q] = 0;
scanf("%d%d%d", &x, &y1, &y2);
if(y1 > y2) swap(y1, y2);
qes[Q] = Question(op, x, y1, y2, Q);
Lsan_Y[++cnt_y] = y1; Lsan_Y[++cnt_y] = y2;
re_tim[++need_out] = Q;
}
}
solve();
return 0;
}