3600: 没有人的算术
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1118 Solved: 452
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
Sample Output
HINT
Source
。。。。神。。神题。。。
具体过程太抽象了。。。我们考虑如果能有一种方法能快速得到排名那就方便多了
考虑用一个平衡树维护排名,
用实数表示排名,对于每一个平衡树上的节点,用这个节点的所属实数区间的中位数作为排名;对于实数区间(根的实数区间自己定),对于右儿子,区间为(mid,r),左儿子区间为(l,mid)
每个节点在保存实数排名的同时,也要保存之前赋值的(l,r)(注意是保存l、r,而不是l、r的实数排名)
然后插入时只需要做平衡树的普通插入即可,
询问用一个线段树维护,每个节点存最大值的下标(即答案)
对于平衡树的选择,因为实数区间要相对静止,所以考虑用替罪羊树
有一个小技巧:可以维护一个id数组表示每个原数组位置现在对应的是替罪羊树上的哪个节点,从而来避免替罪羊树的删除操作(同时也是为了维护相对静止),然后线段树在比较的时候就是比较id的实数排名就好了
PS.我这个板子好像跑很快?
代码:
#include<queue> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<cmath> #include<cstdlib> using namespace std; typedef long long LL; typedef double DL; const int INF = 20011209; const int maxn = 500010; DL f[maxn]; struct data{ int x,y; data(int _x = 0,int _y = 0){x = _x; y = _y;} bool operator == (const data &b) const { return f[x] == f[b.x] && f[y] == f[b.y]; } bool operator < (const data &b) const { return f[x] < f[b.x] || (f[x] == f[b.x] && f[y] < f[b.y]); } bool operator > (const data &b) const { return f[x] > f[b.x] || (f[x] == f[b.x] && f[y] > f[b.y]); } }val[maxn]; int n,m,rt,cnt; int cur[maxn],id[maxn]; int siz[maxn],ch[maxn][2],tot; int stk[maxn],now,p; inline LL getint() { LL ret = 0,f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar(); return ret * f; } inline bool bal(int o) { return max(siz[ch[o][1]],siz[ch[o][0]]) <= 0.77 * siz[o]; } inline void maintain(int o) { siz[o] = siz[ch[o][1]] + siz[ch[o][0]] + 1; } inline void dfs(int o) { if (!o) return; dfs(ch[o][0]); stk[++now] = o; dfs(ch[o][1]); } inline void rebuild(int &o,int l,int r,DL xl,DL xr) { if (l > r) return; int mid = l + r >> 1; o = stk[mid]; siz[o] = 1; f[o] = (xl + xr) / 2; ch[o][0] = ch[o][1] = 0; if (l == r) return; rebuild(ch[o][0],l,mid - 1,xl,(xl + xr) / 2); rebuild(ch[o][1],mid + 1,r,(xl + xr) / 2,xr); maintain(o); return; } inline void Rebuild(int &p,DL L,DL R) { dfs(p); rebuild(p,1,now,L,R); now = 0; } inline int insert(int &o,DL l,DL r,data x) { if (!o) {val[o = ++tot] = x; f[o] = (l + r) / 2.0; maintain(o);} if (x == val[o]) return o; int d = x > val[o],ret = 0; if (!d) ret = insert(ch[o][d],l,(l + r) / 2.0,x); else ret = insert(ch[o][d],(l + r) / 2.0,r,x); maintain(o); if (!bal(o)) Rebuild(o,l,r); return ret; } inline int idmax(int a,int b) { return f[cur[a]] >= f[cur[b]] ? a : b; } inline void update(int o,int l,int r,int pos) { if (l == r) {id[o] = l; return;} int mid = l + r >> 1,lc = o << 1,rc = o << 1 | 1; if (pos <= mid) update(lc,l,mid,pos); else update(rc,mid + 1,r,pos); id[o] = idmax(id[lc],id[rc]); } inline int query(int o,int l,int r,int al,int ar) { if (al <= l && r <= ar) return id[o]; int ret = 0,mid = l + r >> 1,lc = o << 1,rc = o << 1 | 1; if (al <= mid) ret = idmax(ret,query(lc,l,mid,al,ar)); if (mid < ar) ret = idmax(ret,query(rc,mid + 1,r,al,ar)); return ret; } inline char getcom() { char c = getchar(); while (c != 'Q' && c != 'C') c = getchar(); return c; } int main() { n = getint(); m = getint(); f[rt = ++tot] = (0 + INF) / 2.0; val[rt] = (data){0,INF}; siz[tot] = 1; f[0] = -1; for (int i = 1; i <= n; i++) update(1,1,n,i); for (int i = 1; i <= n; i++) cur[i] = 1; for (int i = 1; i <= m; i++) { char c = getcom(); int l = getint(),r = getint(); if (c == 'Q') printf("%d\n",query(1,1,n,l,r)); else { int k = getint(); cur[k] = insert(rt,0,INF,(data){cur[l],cur[r]}); update(1,1,n,k); } return 0; }