noip 2017 列队 (45行!!!!)
题目的话,我扔 https://www.luogu.org/problemnew/show/P3960
这题在仔细思考(看题解)后感觉还是挺简单的。
因为对于每一次操作只会影响当前行和最后一列,那么我们可以用动态开点线段树来维护每一行的前m - 1 个然后在用一个维护最后一列,那么就可以很愉快的A了。
代码(45行有木有!!!!)
#include<bits/stdc++.h>
#define ll long long
#define N 4600005
using namespace std;
int ch[N][2], root[N], del[N], tot, n, m, q, M;
vector<ll> extral[N];
int find(int l, int r, int rt, int x){ // 找当前位置
if(l == r) return l;
int mid = (l + r) >> 1, ret = mid - l + 1 - del[ch[rt][0]];
if(ret >= x) return find(l, mid, ch[rt][0], x);
else return find(mid + 1, r, ch[rt][1], x - ret);
}
void dele(int l, int r, int &rt, int x){ // 删掉当前点
if(!rt) rt = ++ tot;
del[rt] ++;
if(l == r) return;
int mid = (l + r) >> 1;
if(x <= mid) dele(l, mid, ch[rt][0], x);
else dele(mid + 1, r, ch[rt][1], x);
}
ll DL(int x, ll val){ // 删掉最后一行的某一个点并把val 加进去
int pos = find(1, M, root[n + 1], x); ll ans;
dele(1, M, root[n + 1], pos);
if(pos <= n) ans = (ll)pos * m; else ans = extral[n + 1][pos - n - 1];
extral[n + 1].push_back(val?val:ans);
return ans;
}
ll query(int x, int y){ // 处理非最后一行的情况
int pos = find(1, M, root[x], y); ll ans;
dele(1, M, root[x], pos);
if(pos < m) ans = (ll)(x - 1) * m + pos; else ans = extral[x][pos - m];
extral[x].push_back(DL(x, ans));
return ans;
}
int main(){
scanf("%d%d%d", &n, &m, &q);
M = max(n, m) + q;
for(;q --;){
int x, y;
scanf("%d%d", &x, &y);
if(y != m) printf("%lld\n", query(x, y));
else printf("%lld\n", DL(x, 0));
}
return 0;
}//呵呵呵呵呵呵呵呵呵呵呵
注意一下数组要开大一些(log),不然会凉凉。
嘿嘿嘿嘿嘿嘿嘿嘿。
哈哈哈哈哈哈哈哈嗝。