[BOI2007]Mokia 摩基亚
嘟嘟嘟
第一反应是二维树状数组,但是看数据范围就果断放弃了。
不过这题刚好符合了修改互不干扰,可离线的标准,因此\(CDQ\)分治应该可解。
其实这题跟陌上花开很像,只不过第一维是时间,然后第二维是\(x\),最后一维\(y\)用树状数组排序。
接下来是重点:
题解的方法是维护二维前缀和,也就是把这个矩形拆成四个点,分别是\((x_1 - 1, y_1 - 1)\), \((x_1 - 1, y_2)\), \((x_2, y_1 - 1)\), \((x_2, y_2)\)。然后就是正常树状数组维护了。
而我的做法是把这个矩形拆成两条线,即左边的边和右边的边,维护的时候是利用\(y\)的前缀和相减得到区间和。看起来十分有道理,但就是\(50\)分怎么也\(AC\)不了。直到最后快疯了才不得不放弃。
这两个代码我都放上去吧
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define rg register
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 2e5 + 5;
const int maxm = 2e6 + 5;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n, m, cnt = 0;
struct Node
{
int x, y, id, w;
ll ans;
bool operator < (const Node& oth)const
{
return id < oth.id;
}
}t[maxn], a[maxn];
ll c[maxm];
int lowbit(int x)
{
return x & -x;
}
void erase(int pos)
{
for(; pos <= m; pos += lowbit(pos))
if(c[pos] != 0) c[pos] = 0;
else break;
}
void add(int pos, int d)
{
for(; pos <= m; pos += lowbit(pos)) c[pos] += d;
}
ll query(int pos)
{
ll ret = 0;
for(; pos; pos -= lowbit(pos)) ret += c[pos];
return ret;
}
ll ans[maxn];
int st[maxn], top = 0;
void cdqSolve(int L, int R)
{
if(L == R) return;
int mid = (L + R) >> 1, id1 = L, id2 = mid + 1;
cdqSolve(L, mid); cdqSolve(mid + 1, R);
for(int i = L; i <= R; ++i)
{
if(id2 > R || (id1 <= mid && a[id1].x <= a[id2].x))
{
t[i] = a[id1++];
if(!t[i].id) add(t[i].y, t[i].w);
}
else
{
t[i] = a[id2++];
if(t[i].id) t[i].ans += query(t[i].y);
}
}
for(int i = L; i <= mid; ++i) if(!a[i].id) erase(a[i].y);
for(int i = L; i <= R; ++i) a[i] = t[i];
}
int main()
{
scanf("0 %d", &m);
int op;
while(scanf("%d", &op) && op != 3)
{
if(op == 1)
{
int x = read(), y = read(), w = read();
a[++n] = (Node){x, y, 0, w, 0};
}
else if(op == 2)
{
int xa = read(), ya = read(), xb = read(), yb = read();
a[++n] = (Node){xa - 1, ya - 1, n, 0, 0};
a[++n] = (Node){xa - 1, yb, n, 0, 0};
a[++n] = (Node){xb, ya - 1, n, 0, 0};
a[++n] = (Node){xb, yb, n, 0, 0};
}
}
cdqSolve(1, n);
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; ++i)
if(a[i].id)
{
write(a[i + 3].ans - a[i + 1].ans - a[i + 2].ans + a[i].ans), enter;
i += 3;
}
return 0;
}
然后是我的神一般的$50$分代码。 ```c++ #include
int n, m, s, cnt = 0;
struct Node
{
int x, y1, y2, id; bool flg1, flg2; //flg1:query or update flg2:square start or end
bool operator < (const Node& oth)const
{
if(x != oth.x) return x < oth.x;
if(flg1 != oth.flg1)
{
if(flg1 == 1) return oth.flg2 == 1;
else return flg2 == 0;
}
return 1;
}
}t[maxn], a[maxn];
ll c[maxm];
int lowbit(int x)
{
return x & -x;
}
void erase(int pos)
{
for(; pos <= m; pos += lowbit(pos))
if(c[pos] != 0) c[pos] = 0;
else break;
}
void add(int pos, int d)
{
for(; pos <= m; pos += lowbit(pos)) c[pos] += d;
}
ll query(int pos)
{
ll ret = 0;
for(; pos; pos -= lowbit(pos)) ret += c[pos];
return ret;
}
ll ans[maxn];
int st[maxn], top = 0;
void cdqSolve(int L, int R)
{
if(L == R) return;
int mid = (L + R) >> 1, id1 = L, id2 = mid + 1;
cdqSolve(L, mid); cdqSolve(mid + 1, R);
for(int i = L; i <= R; ++i)
{
if(id2 > R || (id1 <= mid && a[id1] < a[id2]))
{
t[i] = a[id1++];
if(t[i].flg1)
{
st[++top] = i;
add(t[i].y1, t[i].y2);
}
}
else
{
t[i] = a[id2++];
if(!t[i].flg1)
{
ll sum = query(t[i].y2) - query(t[i].y1 - 1);
if(!t[i].flg2) ans[t[i].id] -= sum;
else ans[t[i].id] += sum;
}
}
}
for(int i = L; i <= R; ++i) a[i] = t[i];
for(int i = 1; i <= top; ++i) erase(t[st[i]].y1);
top = 0;
}
int main()
{
s = read(); m = read();
int op;
while(scanf("%d", &op) && op != 3)
{
if(op == 1)
{
int x = read(), y = read(), w = read();
a[++n] = (Node){x, y, w, 0, 1, 0};
}
else if(op == 2)
{
int xa = read(), ya = read(), xb = read(), yb = read();
a[++n] = (Node){xa, ya, yb, ++cnt, 0, 0};
a[++n] = (Node){xb, ya, yb, cnt, 0, 1};
ans[cnt] += (ll)(xb - xa + 1) * (ll)(yb - ya + 1) * s;
}
}
cdqSolve(1, n);
for(int i = 1; i <= cnt; ++i) write(ans[i]), enter;
return 0;
}