1. 程式人生 > >noip 2017 列隊 (45行!!!!)

noip 2017 列隊 (45行!!!!)

這題在仔細思考(看題解)後感覺還是挺簡單的。

因為對於每一次操作只會影響當前行和最後一列,那麼我們可以用動態開點線段樹來維護每一行的前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),不然會涼涼。

嘿嘿嘿嘿嘿嘿嘿嘿。

哈哈哈哈哈哈哈哈嗝。