WuliWuliiii
凤兮凤兮归故乡 遨游四海求其凰

题目链接

  

题目描述

Sylvia 是一个热爱学习的女孩子。

前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。

Sylvia 所在的方阵中有n×mn×m名学生,方阵的行数为 nn,列数为 mm。

为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 1 到 n×mn×m 编上了号码(参见后面的样例)。即:初始时,第 ii 行第 jj 列 的学生的编号是(i−1)×m+j(i1)×m+j。

然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了 qq件这样的离队事件。每一次离队事件可以用数对(x,y)(1≤x≤n,1≤y≤m)(x,y)(1xn,1ym)描述,表示第 xx 行第 yy 列的学生离队。

在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达 这样的两条指令:

  1. 向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条 指令之后,空位在第 xx 行第 mm列。

  2. 向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条 指令之后,空位在第 nn 行第 mm列。

教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后, 下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 nn 行 第 mm 列一个空位,这时这个学生会自然地填补到这个位置。

因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学 的编号是多少。

注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后 方阵中同学的编号可能是乱序的。

输入输出格式

输入格式:

 

输入共 q+1q+1 行。

第 1 行包含 3 个用空格分隔的正整数 n,m,qn,m,q,表示方阵大小是 nn 行 mm 列,一共发 生了 qq 次事件。

接下来 qq 行按照事件发生顺序描述了 qq 件事件。每一行是两个整数 x,yx,y,用一个空 格分隔,表示这个离队事件中离队的学生当时排在第 xx 行第 yy 列。

 

输出格式:

 

按照事件输入的顺序,每一个事件输出一行一个整数,表示这个离队事件中离队学 生的编号。

 

  刚拿到这道题的时候,的确是无从下手的感觉,知道有这样的一道题,【SCOI2006】动态最值,这样一道题,但是那道题是维护再一维空间上的删除并且挪动这样的一个操作,我们对于那道题只需要开线段树去维护(甚至不需要可持久化维护),维护的是size,也就是这段区间上有几个数,然后我们直接维护对应的最小值和最大值即可,线段树区间的长度就是原来的N个数的长度(因为只有N个数的说,并且还是只有删除操作)。然后一开始的时候,我们直接buildtree,并且直接赋值即可,然后在后面的找区间的时候,左区间超过L个数、右区间共有R个数,这样的(用size来维护)。

这里讲一下该怎么去维护:

我们假设左子树有X个节点,向右区间查找的时候,记得减去X,

如果ql<=X && qr>X,那么我们左右都要查;

如果ql>X && qr>X,那么我们直接查右区间;

如果ql<=X && qr<=X,我们只查左区间。

同样的,我们也可以删除。

  讲了这么多与这道题没有关系的,接下来回归到正题上来。

  思路:上面讲了这些,是为了开拓在可持久化线段树上的思路的,并且用到这道题就可以了。关键在于是怎么用?这道题会有这样的两种操作,一种是我们拎出来的人在第M列,那么他就不需要(操作1)向左移动了,直接向前移动即可;另一种是他不在第M列,此时我们就要考虑他要先向左移动,然后在向前对齐(向前对齐的时候,是不是就是可以看成我们挪动的是第M列的数)。

  有了这些思路之后,就可以开始写了,因为这里的区间长度会比较的大,很显然,我们不能去用线段树来直接维护,那么就是需要用到可持久化线段树了,先想个办法维护一下在第M列时候的情况,因为这时候我们只需要向前看齐就可以了,那么我们是不是可以看成单链的一维空间那样子的想法(就是上面的思想了),但是这里需要补,怎么补就是个问题了,我们在这里可以开一个vector<>来存,把每个最后的值就是直接pushback就可以了。

  那么,假如我们拎出去的人不是第M列的怎么办呢?假如拎出去的人的坐标是(x, y),那么我们是不是要去x这一行去找到y位的这个数,然后得到他的实际值,这时候(x, y)这个点空出来了,先要这一列的其他人都靠过来,然后再是第M列的人往前走,靠过来的做法与之前一维的时候相同,但是第M列的人向前走呢,我们可以看到M列的人,从第x位开始空出来,后面的人向前走,是不是就可以相当是第x位以后的点都向前移了一位,而查第M列的第x位不就是查其后面的数呢,然后这时候,就要把原来(x, y)上的值给赋值到M列的最后一个,也就是pushback()进去即可,同时还要把在M列x行后面的x+1行的值给塞到第x行的pushback后面去。

 

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cmath>
  4 #include <string>
  5 #include <cstring>
  6 #include <algorithm>
  7 #include <limits>
  8 #include <vector>
  9 #include <stack>
 10 #include <queue>
 11 #include <set>
 12 #include <map>
 13 #define lowbit(x) ( x&(-x) )
 14 #define pi 3.141592653589793
 15 #define e 2.718281828459045
 16 #define INF 0x3f3f3f3f
 17 #define HalF (l + r)>>1
 18 #define lsn rt<<1
 19 #define rsn rt<<1|1
 20 #define Lson lsn, l, mid
 21 #define Rson rsn, mid+1, r
 22 #define QL Lson, ql, qr
 23 #define QR Rson, ql, qr
 24 #define myself rt, l, r
 25 namespace fastIO {
 26 #define BUF_SIZE 100000
 27     //fread -> read
 28     bool IOerror = 0;
 29     inline char nc() {
 30         static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
 31         if(p1 == pend) {
 32             p1 = buf;
 33             pend = buf + fread(buf, 1, BUF_SIZE, stdin);
 34             if(pend == p1) {
 35                 IOerror = 1;
 36                 return -1;
 37             }
 38         }
 39         return *p1++;
 40     }
 41     inline bool blank(char ch) {
 42         return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
 43     }
 44     inline void read(int &x) {
 45         char ch;
 46         while(blank(ch = nc()));
 47         if(IOerror) return;
 48         for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
 49     }
 50 #undef BUF_SIZE
 51 };
 52 using namespace fastIO;
 53 using namespace std;
 54 typedef unsigned long long ull;
 55 typedef long long ll;
 56 const int maxN = 6e5 + 7;
 57 int N, M, Q, root[maxN], _UP, lc[30 * maxN], rc[30 * maxN], siz[30 * maxN], tot;
 58 vector<ll> vt[maxN];
 59 inline void insert(int &rt, int l, int r, int k)
 60 {
 61     if(!rt) rt = ++tot;
 62     siz[rt]++;
 63     if(l == r) return;
 64     int mid = HalF;
 65     if(k <= mid) insert(lc[rt], l, mid, k);
 66     else insert(rc[rt], mid + 1, r, k);
 67 }
 68 int query(int rt, int l, int r, int k)
 69 {
 70     if(l == r) return l;
 71     int mid = HalF, size_L = mid - l + 1 - siz[lc[rt]];
 72     if(k <= size_L) return query(lc[rt], l, mid, k);
 73     else return query(rc[rt], mid + 1, r, k - size_L);
 74 }
 75 inline ll del_M_las(int x, ll val)    //如果这个人是最后那一排的话,就不需要向左看齐了
 76 {
 77     int pos = query(root[N + 1], 1, _UP, x);    insert(root[N + 1], 1, _UP, pos);
 78     ll ans = pos <= N ? (ll)pos * (ll)M : vt[N + 1][pos - N - 1];
 79     vt[N + 1].push_back(val ? val : ans);
 80     return ans;
 81 }
 82 inline ll del_N(int x, int y)
 83 {
 84     int pos = query(root[x], 1, _UP, y);    insert(root[x], 1, _UP, pos);
 85     ll ans = pos < M ? (ll)(x - 1) * (ll)M + pos : vt[x][pos - M];
 86     vt[x].push_back(del_M_las(x, ans));
 87     return ans;
 88 }
 89 int main()
 90 {
 91     tot = 0;
 92     scanf("%d%d%d", &N, &M, &Q);
 93     //read(N);    read(M);    read(Q);
 94     _UP = max(N, M) + Q;
 95     int x, y;
 96     while(Q--)
 97     {
 98         scanf("%d%d", &x, &y);
 99         //read(x);    read(y);
100         if(y == M) printf("%lld\n", del_M_las(x, 0));
101         else printf("%lld\n", del_N(x, y));
102     }
103     return 0;
104 }
View Code

 

posted on 2019-05-09 22:45  唔哩Wulili  阅读(400)  评论(0编辑  收藏  举报