您的位置:首页 > 其它

[BZOJ1201][HNOI2005]数三角形(树状数组)

2018-02-20 19:47 225 查看
下面定义(i,j)(i,j)表示第ii行的第jj个顶点(共n+1n+1行,第ii行有ii个顶点)

考虑一个朴素的做法:

一、利用递推,预处理出55个值:

(1)lef[i][j]lef[i][j]:(i,j)(i,j)通过未被删除的边,向左延伸的最长距离,如样例中lef[3][3]=0lef[3][3]=0,lef[4][4]=3lef[4][4]=3。

(2)leup[i][j]leup[i][j]:(i,j)(i,j)通过未被删除的边,向左上延伸的最长距离。

(3)riup[i][j]riup[i][j]:(i,j)(i,j)通过未被删除的边,向右上延伸的最长距离。

(4)ledw[i][j]ledw[i][j]:(i,j)(i,j)通过未被删除的边,向左下延伸的最长距离。

(5)ridw[i][j]ridw[i][j]:(i,j)(i,j)通过未被删除的边,向右下延伸的最长距离。

统计正立三角形时,先枚举右下顶点(i,j)(i,j)。容易得出,

右下顶点为(i,j)(i,j)的正立三角形个数不超过min(lef[i][j],leup[i][j])min(lef[i][j],leup[i][j])。

记k=j−min(lef[i][j],leup[i][j])k=j−min(lef[i][j],leup[i][j]),那么第ii行的第[k,j−1][k,j−1]个顶点都有可能成为正立三角形的左下角。

而对于任何的h∈[k,j−1]h∈[k,j−1],(i,h)(i,h)向右上延伸后,能与(i,j)(i,j)构成正立三角形的充分必要条件是:

riup[i][h]≥j−hriup[i][h]≥j−h

统计倒立三角形也一样,先枚举右上顶点(i,j)(i,j),

右上顶点为(i,j)(i,j)的正立三角形个数不超过min(lef[i][j],ledw[i][j])min(lef[i][j],ledw[i][j])。

记k=j−min(lef[i][j],ledw[i][j])k=j−min(lef[i][j],ledw[i][j]),那么第ii行的第[k,j−1][k,j−1]个顶点都有可能成为倒立三角形的左上角。

对于任何的h∈[k,j−1]h∈[k,j−1],(i,h)(i,h)向右下延伸后,能与(i,j)(i,j)构成倒立三角形的充分必要条件是:

ridw[i][h]≥j−hridw[i][h]≥j−h

复杂度是O(n3)O(n3)的。考虑将上面给出的两个不等式移项:

riup[i][h]+h≥jriup[i][h]+h≥j

ridw[i][j]+h≥jridw[i][j]+h≥j

这样就转换成了求一个区间内,有多少个数大于一个定值。将询问离线排序之后,可以使用树状数组解决。复杂度O(n2logn)O(n2log⁡n)。

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1024, M = 4096;
int n, led

, rid

, lef

, leu

, riu

, T[M], tot; ll ans;
void change(int x, int v) {
for (; x <= 4000; x += x & -x) T[x] += v;
}
int ask(int x) {
int res = 0; for (; x; x -= x & -x) res += T[x]; return res;
}
struct cyx {
int id, ri;
cyx() {}
cyx(int _id, int _ri) : id(_id), ri(_ri) {}
} otz[M];
inline bool comp(const cyx &a, const cyx &b) {
return a.ri > b.ri;
}
int main() {
int i, j, x, y, z; n = read();
for (i = 1; i <= n; i++) for (j = 1; j <= i; j++) {
x = read(); y = read(); z = read();
lef[i + 1][j + 1] = z; led[i][j] = riu[i + 1][j] = x;
rid[i][j] = leu[i + 1][j + 1] = y;
}
n++; for (i = 1; i <= n; i++) for (j = 1; j <= i; j++)
lef[i][j] = lef[i][j] ? lef[i][j - 1] + 1 : 0;
for (j = 1; j <= n; j++) for (i = j; i <= n; i++) {
leu[i][j] = leu[i][j] ? leu[i - 1][j - 1] + 1 : 0;
riu[i][j] = riu[i][j] ? riu[i - 1][j] + 1 : 0;
}
for (i = n; i; i--) for (j = 1; j <= i; j++) {
led[i][j] = led[i][j] ? led[i + 1][j] + 1 : 0;
rid[i][j] = rid[i][j] ? rid[i + 1][j + 1] + 1 : 0;
}
for (i = 1; i <= n; i++) for (j = 1; j <= i; j++)
riu[i][j] += j, rid[i][j] += j;
for (i = 1; i <= n; i++) {
for (j = 0; j <= 4000; j++) T[j] = 0; tot = 0;
for (j = 1; j <= i; j++) otz[++tot] = cyx(j, riu[i][j]);
sort(otz + 1, otz + tot + 1, comp); int orz = 1;
for (j = i; j; j--) {
while (orz <= tot && otz[orz].ri >= j)
change(otz[orz].id, 1), orz++;
ans += ask(j - 1) - ask(j - min(lef[i][j], leu[i][j]) - 1);
}
for (j = 0; j <= 4000; j++) T[j] = 0; tot = 0;
for (j = 1; j <= i; j++) otz[++tot] = cyx(j, rid[i][j]);
sort(otz + 1, otz + tot + 1, comp); orz = 1;
for (j = i; j; j--) {
while (orz <= tot && otz[orz].ri >= j)
change(otz[orz].id, 1), orz++;
ans += ask(j - 1) - ask(j - min(lef[i][j], led[i][j]) - 1);
}
}
cout << ans << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: