2021牛客寒假算法基础集训营4 G. 九峰与蛇形填数(线段树)
九峰与蛇形填数
https://ac.nowcoder.com/acm/problem/218456
Description
Solution
显然对于每个方格上的数字都可能被多次覆盖,但是真正起作用的是最后一次覆盖的时候。
考虑一个问题:如果我知道某个点最后一次覆盖是第几次操作,那么意味着我知道最后一次覆盖的方阵初始点与边长,能不能推算当前点的值呢?
显然是可以的——这个自己手推一下吧, 应该几分钟就能推出来了。具体想法是以两行作为一个周期,相差奇数行就特殊处理一下(因为方向是反过来的)。
那么我们只需要每次操作的时候对于被操作的区域进行标记,如果当前已被标记就重新覆盖,最后查询该点的标记,通过标记使用上述的方法得到最终值即可。考虑到 , 不能暴力打标记。选择开2000个线段树,使用线段树的
实现
的区间赋值,最后每次
查询当前点的值,总体时间复杂度
。但线段树有点卡常(我的代码
),而且比较玄学,个人觉得这题时间应该放得再宽一些。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, M = 1e7 + 10, mod = 1e9 + 7;
struct node {
struct point {
int l, r, lazy;
} t[2005 << 2];
void push_down(int rt) {
if (t[rt].lazy) {
t[rt << 1].lazy = t[rt].lazy;
t[rt << 1 | 1].lazy = t[rt].lazy;
t[rt].lazy = 0;
}
}
void build(int rt, int l, int r) {
t[rt].l = l, t[rt].r = r;
t[rt].lazy = 0;
if (l == r) {
return ;
}
int mid = t[rt].l + t[rt].r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
}
void update(int rt, int ql, int qr, int val) {
if (ql <= t[rt].l && qr >= t[rt].r) {
t[rt].lazy = val;
return ;
}
int mid = t[rt].l + t[rt].r >> 1;
push_down(rt);
if (ql > mid) {
update(rt << 1 | 1, ql, qr, val);
} else if (qr <= mid) {
update(rt << 1, ql, qr, val);
} else {
update(rt << 1, ql, mid, val);
update(rt << 1 | 1, mid + 1, qr, val);
}
}
int query(int rt, int ql) {
if (t[rt].l == t[rt].r) {
return t[rt].lazy;
}
push_down(rt);
int mid = t[rt].l + t[rt].r >> 1;
if (ql <= mid) {
return query(rt << 1, ql);
} else {
return query(rt << 1 | 1, ql);
}
}
}tree[2005];
struct Query {
int x, y, k;
}Q[3005];
int cal(int n, int x, int y, int k, int i, int j) {
int tmpx = i - x;
int res = 1 + tmpx * k;
if (tmpx & 1) {
res += (y + k - 1 - j);
} else {
res += (j - y);
}
return res;
}
void solve() {
int n, m; scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
tree[i].build(1, 1, n);
}
for (int i = 1; i <= m; i++) {
scanf("%d %d %d", &Q[i].x, &Q[i].y, &Q[i].k);
for (int j = Q[i].x; j <= Q[i].x + Q[i].k - 1; j++) {
tree[j].update(1, Q[i].y, Q[i].y + Q[i].k - 1, i);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int now = tree[i].query(1, j);
if (!now) {
printf("0 ");
} else {
int x = Q[now].x, y = Q[now].y, k = Q[now].k;
printf("%d ", cal(n, x, y, k, i, j));
}
}
puts("");
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T = 1; //cin >> T;
while (T--) {
solve();
}
return 0;
}
阿里巴巴灵犀互娱公司福利 649人发布