传送门

Luogu

解题思路

一眼平衡树,应该没问题吧?

但我们一定要反应过来,单点的维护是非常之困难的,因为这是一个网格图而不仅仅是一条序列。

我们要考虑把修改操作全都放在序列上进行。

其实题面里是给了提示的,找一找在哪里。

于是我们可以考虑维护一些区间:

对于每一行,将前 \(m-1\) 个数的区间作为一个节点;将最后一列的 \(n\) 个数的的区间作为一个节点。

但是我们会遇到这样一个问题:当前的区间需要被切开,也就是要把一个节点分裂成两个节点。

其实这个和普通的序列操作是没什么区别的,具体实现看看代码就很显然了。

细节注意事项

  • 节点空间开两倍
  • long long

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#define rg register
using namespace std;
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
} typedef long long LL;
const int _ = 3000002 * 2; int n, m, q, rt[_];
int tot, siz[_], pri[_], lc[_], rc[_];
LL r[_], l[_]; inline int newnode(LL L, LL R)
{ return siz[++tot] = R - L + 1, r[tot] = R, l[tot] = L, pri[tot] = rand(), tot; } inline void pushup(int p) { siz[p] = siz[lc[p]] + siz[rc[p]] + r[p] - l[p] + 1; } inline int merge(int x, int y) {
if (!x || !y) return x + y;
if (pri[x] > pri[y])
return rc[x] = merge(rc[x], y), pushup(x), x;
else
return lc[y] = merge(x, lc[y]), pushup(y), y;
} inline void _split(int p, int k) {
if (k >= r[p] - l[p] + 1) return ;
LL pos = l[p] + k - 1;
int New = newnode(pos + 1, r[p]);
return r[p] = pos, rc[p] = merge(New, rc[p]), pushup(p);
} inline void split(int p, int k, int& x, int& y) {
if (!p) { x = y = 0; return ; }
if (siz[lc[p]] >= k)
return y = p, split(lc[p], k, x, lc[y]), pushup(p);
else { _split(p, k - siz[lc[p]]);
return x = p, split(rc[p], k - siz[lc[p]] - (r[p] - l[p] + 1), rc[x], y), pushup(p);
}
} int main() {
#ifndef ONLINE_JUDGE
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
srand(time(0));
read(n), read(m), read(q);
for (rg int i = 1; i <= n; ++i)
rt[i] = newnode((LL) (i - 1) * m + 1, (LL) i * m - 1);
for (rg int i = 1; i <= n; ++i)
rt[n + 1] = merge(rt[n + 1], newnode((LL) i * m, (LL) i * m));
for (rg int x, y; q--; ) {
read(x), read(y);
if (y == m) {
int a, b, c;
split(rt[n + 1], x, a, c);
split(a, x - 1, a, b);
printf("%lld\n", l[b]);
rt[n + 1] = merge(a, merge(c, b));
} else {
int a, b, c, aa, bb, cc;
split(rt[x], y, a, c);
split(a, y - 1, a, b);
printf("%lld\n", l[b]);
split(rt[n + 1], x, aa, cc);
split(aa, x - 1, aa, bb);
rt[x] = merge(a, merge(c, bb));
rt[n + 1] = merge(aa, merge(cc, b));
}
}
return 0;
}

完结撒花 \(qwq\)

最新文章

  1. ios调用c#后台接口报文格式
  2. eclipse中改变默认的workspace的方法及说明
  3. [ActionScript 3.0] as3可以通过CDATA标签声明多行字符串
  4. JS常用的设计模式(14)—— 备忘录模式
  5. ios开发--常用宏定义(部分转)
  6. Enum(枚举)示例
  7. Js动态传递不定数目的参数
  8. UESTC_Can You Help God Wu CDOJ 582
  9. HDU 2717 Catch That Cow
  10. fedora audacious 不能播放音乐
  11. &lt;context-param&gt;与&lt;init-param&gt;的区别与作用(转)
  12. android中自定义shape
  13. HDU 5804 Price List
  14. --@angularJS--简单的带嵌套的指令demo
  15. React入门---开始前的准备(上)-2
  16. iOS获取WIFI的IP、子网掩码,以及域名转IP
  17. linux-2.6.18源码分析笔记---信号
  18. c/c++再学习:常用字符串转数字操作
  19. DAY13、迭代器,生成器,枚举
  20. 《xxx系统》可用性与易用性功能增加

热门文章

  1. 【转载】IntelliJ IDEA配置JUnit进行单元测试
  2. sqlserver数据将多个表或视图的数据合并到一个表或视图里的sql语句
  3. 实时监听 mysql 操作,Linux 版
  4. Java IO流详解(五)——缓冲流
  5. 高级T-SQL进阶系列 (一)【下篇】:使用 CROSS JOIN 介绍高级T-SQL
  6. idea提交项目到码云
  7. 看完这篇微服务架构设计思想,90%的Java程序员都收藏了
  8. PAT A1091 Acute Stroke
  9. SZWI3800
  10. Java基础 -4.4