noip2017D2T3的几种写法...(BIT/线段树/平衡树)
题意各大oj上都有啦..想必来搜题解的都看过题面了...Qw
Solution1:
首先观察n=1的情况,显然就是中间删掉一个数后面加上一个数,并查询那个删掉的数(以后把这样一个过程称为一个操作啦((:)..
就是你用什么都可以写..
然后发现,完整的数据范围就是n+1个n=1的子问题
就是前n行每行前m-1个数的n个子问题和最后一列的子问题..(有点乱乱啊..语文差..
然而开n+1棵什么什么树肯定MLE.....下面以线段树为例
:注意到一次操作,最多更改2log(n)个点,于是就可以愉快动态开点啦(^:
(稍稍借鉴了一下jxc的写法,,好短好妙妙啊
#include<bits/stdc++.h> using namespace std; const int M = 300000; struct Node{ Node *lc, *rc; int l, r, val; Node(int l = 1, int r = M << 1) { this->lc = this->rc = NULL; this->l = l; this->r = r; this->val = r - l + 1; } }; struct SegTree{ Node *rt; vector<long long> add; SegTree(void) { rt = new Node(); add.clear(); } int Del(Node *p, int x) { p->val--; if(p->l == p->r) return p->l; int mid = (p->l + p->r) >> 1; int lcv = p->lc ? p->lc->val : mid - p->l + 1; if(lcv >= x) { if(!p->lc) p->lc = new Node(p->l, mid); return Del(p->lc, x); } else { if(!p->rc) p->rc = new Node(mid + 1, p->r); return Del(p->rc, x - lcv); } } }line[M + 10], row; int n, m, q, x, y; long long now; int main(void) { scanf("%d%d%d", &n, &m, &q); while(q--) { scanf("%d%d", &x, &y); int id = row.Del(row.rt, x); if(id <= n) now = 1LL * id * m; else now = row.add[id - n - 1]; if(y != m) { line[x].add.push_back(now); int id = line[x].Del(line[x].rt, y); if(id < m) now = 1LL * (x - 1) * m + id; else now = line[x].add[id - m]; } row.add.push_back(now); printf("%lld\n", now); } return 0; }
Solution2:
注意到BIT不能动态开点(至少我不会啊ov
于是考虑离线,稍微思考一下,,,,于是发现每一行的查询是独立的,也就是说可以离线之后只开一个BIT
然后把每一行处理完之后再扔回去就可以保证所有行的查询操作是log的
这样就预处理完啦
剩下的就跟之前的一样做就行了(包括那一列的(因为那一列的操作每次都有啊..
#include<bits/stdc++.h> using namespace std; const int M = 300100; int val[M << 1]; vector<pair<int, int> > query[M]; inline void Add(int x, int y) { for(; x <= M << 1; x += -x & x) val[x] += y; } inline int Qry(int x) { int res = 0; for(int i = 19; i >= 0; i--) if((1 << i) + res <= (M << 1)) { if(val[res + (1 << i)] < x) { res += 1 << i; x -= val[res]; } } return res + 1; } void Get_num(int *a, int x) { for(int i = 0; i < query[x].size(); i++) { pair<int, int> o = query[x][i]; a[o.second] = Qry(o.first); Add(a[o.second], -1); } for(int i = 0; i < query[x].size(); i++) { pair<int, int> o = query[x][i]; Add(a[o.second], 1); } } long long now; vector<long long> last[M]; int n, m, q, x, y, qx[M], qy[M], row[M]; int Read(void) { int x = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); return x; } int main(void) { scanf("%d%d%d", &n, &m, &q); for(int i = 1; i <= q; i++) { x = Read(); y = Read(); if(y != m) query[x].push_back(make_pair(y, i)); qx[i] = x, qy[i] = y; } for(int i = 1; i <= M << 1; i++) Add(i, 1); for(int i = 1; i <= n; i++) Get_num(row, i); for(int i = 1; i <= q; i++) { int id = Qry(qx[i]); Add(id, -1); if(id <= n) now = 1LL * id * m; else now = last[0][id - n - 1]; if(qy[i] < m) { last[qx[i]].push_back(now); int id = row[i]; if(id < m) now = 1LL * (qx[i] - 1) * m + id; else now = last[qx[i]][id - m]; } last[0].push_back(now); printf("%lld\n", now); } return 0; }
Solution3:
据说可以trie做.....不会...