3600: 没有人的算术
2017-01-21 23:06
316 查看
3600: 没有人的算术
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 616 Solved: 280
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
Sample Output
HINT
Source
湖北省队互测Week1
[Submit][Status][Discuss]
可以发现,每时每刻新增的元素加入之前元素组成的集合中,
新集合内的元素两两之间一定可以找出严格的大小关系
考虑用某数据结构维护已知集合内的元素,支持O(logn)查询,插入之类
考虑当前新增第k个元素,前k - 1个元素的大小关系已经能在这个数据结构里体现了
不妨给每个点一个实数,这样之前元素的比较就可以直接通过实数比较进行
实数如何选取?给予每个节点一个区间[L,R],定义该节点的势能phi[x] = (L[x] + R[x]) / 2
这样通过势能比较就行了,能够比较,能够查询,此题的大部分操作就已经解决
询问的话,用个线段树维护维护就完成了
最后,数据结构的选择,不妨使用替罪羊树,因为区间的限制,使得节点之间的关系要相对静态
替罪羊树的话,就是选取一个定值alpha,对于某个节点,如果其较大的子树的大小超过该点size * alpha,
则标记这个点,每次插入操作,将标记最浅的那个子树暴力重构成一棵完全二叉树
具体的证明可见CLJ2013年的论文
第一遍写的时候fa[]和rt没有维护好(重构可能改变的东西= =)
人傻不能怪社会系列。。。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<vector> #include<queue> #include<set> #include<map> #include<stack> #include<bitset> #include<ext/pb_ds/priority_queue.hpp> using namespace std; const int maxn = 1E5 + 10; const int maxm = 5E5 + 50; const int T = 4; typedef double DB; const DB alpha = 0.666; const DB eps = 1E-9; DB lp,rp,siz[maxm],phi[maxm],L[maxm],R[maxm]; int n,m,cnt,rt,tp,p,Now,Ans,fa[maxm],id[maxn*T] ,pos[maxn*T],ch[maxm][2],s[maxm],lc[maxm],rc[maxm]; int getint() { char ch = getchar(); int ret = 0; while (ch < '0' || '9' < ch) ch = getchar(); while ('0' <= ch && ch <= '9') ret = ret*10 + ch - '0',ch = getchar(); return ret; } int getcom() { char ch = getchar(); while (ch != 'C' && ch != 'Q') ch = getchar(); return ch == 'C' ? 1 : 2; } int cmp(const int &x,const int &y) { if (lc[x] == lc[y] && rc[x] == rc[y]) return 2; if (lc[x] == lc[y]) return phi[rc[x]] < phi[rc[y]] ? 1 : 0; return phi[lc[x]] < phi[lc[y]] ? 1 : 0; } void maintain(int o) { int ls = (o<<1),rs = (o<<1|1); int d = cmp(id[ls],id[rs]); if (d == 1) pos[o] = pos[rs],id[o] = id[rs]; else pos[o] = pos[ls],id[o] = id[ls]; } void Build(int o,int l,int r) { if (l == r) {id[o] = 1; pos[o] = l; return;} int mid = (l + r) >> 1; Build(o<<1,l,mid); Build(o<<1|1,mid+1,r); maintain(o); } void Modify(int o,int l,int r,int k,int ID) { if (l == r) {id[o] = ID; return;} int mid = (l + r) >> 1; if (k <= mid) Modify(o<<1,l,mid,k,ID); else Modify(o<<1|1,mid+1,r,k,ID); maintain(o); } int Get_id(int o,int l,int r,int k) { if (l == r) return id[o]; int mid = (l + r) >> 1; if (k <= mid) return Get_id(o<<1,l,mid,k); else return Get_id(o<<1|1,mid+1,r,k); } void Get_pos(int o,int l,int r,int ql,int qr) { if (ql <= l && r <= qr) { int d = cmp(id[o],Now); if (d == 0) Now = id[o],Ans = pos[o]; else if (d == 2) Ans = min(Ans,pos[o]); return; } int mid = (l + r) >> 1; if (ql <= mid) Get_pos(o<<1,l,mid,ql,qr); if (qr > mid) Get_pos(o<<1|1,mid+1,r,ql,qr); } int Query(int x,int now) { if (!x) return x; int d = cmp(x,now); if (d == 2) return x; return Query(ch[x][d],now); } void Insert(int &x,int now,DB LP,DB RP) { if (!x) { x = now; phi[x] = (LP + RP) / 2.00; L[x] = LP; R[x] = RP; siz[x] = 1.00; return; } DB mid = (LP + RP) / 2.00; int d = cmp(x,now); if (!d) Insert(ch[x][d],now,L[x],mid); else Insert(ch[x][d],now,mid,R[x]); fa[ch[x][d]] = x; siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1.00; if (siz[ch[x][d]] >= alpha * siz[x]) p = x,lp = L[x],rp = R[x]; } void Dfs(int x) { if (!x) return; Dfs(ch[x][0]); s[++tp] = x; Dfs(ch[x][1]); } int Build_tree(int l,int r,DB LP,DB RP) { if (l > r) return 0; int mid = (l + r) >> 1; int k = s[mid]; phi[k] = (LP + RP) / 2.00; ch[k][0] = Build_tree(l,mid-1,LP,phi[k]); ch[k][1] = Build_tree(mid+1,r,phi[k],RP); siz[k] = 1.00; L[k] = LP; R[k] = RP; for (int i = 0; i < 2; i++) if (ch[k][i]) fa[ch[k][i]] = k,siz[k] += siz[ch[k][i]]; return k; } void Rebuild() { tp = 0; Dfs(p); int q = fa[p],now = Build_tree(1,tp,lp,rp); if (!q) rt = now,fa[now] = 0; else ch[q][ch[q][1] == p] = now,fa[now] = q; } int main() { #ifdef DMC freopen("DMC.txt","r",stdin); #endif n = getint(); m = getint(); rt = cnt = 1; R[rt] = 1E9; phi[rt] = (L[rt] + R[rt]) / 2.00; Build(1,1,n); while (m--) { int typ = getcom(),l,r; l = getint(); r = getint(); if (typ == 1) { int k = getint(); ++cnt; lc[cnt] = Get_id(1,1,n,l); rc[cnt] = Get_id(1,1,n,r); int ret = Query(rt,cnt); if (ret) Modify(1,1,n,k,ret),--cnt; else { Modify(1,1,n,k,cnt); p = 0; Insert(rt,cnt,L[rt],R[rt]); if (p) Rebuild(); } } else { Now = 1; Ans = maxn; Get_pos(1,1,n,l,r); printf("%d\n",Ans); } } return 0; }
相关文章推荐
- 【替罪羊树-动态标号+线段树】BZOJ3600[没有人的算术]题解
- 【bzoj3600】没有人的算术
- [BZOJ3600][没有人的算术][替罪羊树+线段树]
- [bzoj3600]没有人的算术
- bzoj 3600 没有人的算术 - 替罪羊树 - 线段树
- bzoj 3600: 没有人的算术
- [替罪羊树 动态标号 线段树] BZOJ 3600 没有人的算术
- bzoj 3600: 没有人的算术 替罪羊树+线段树
- [BZOJ3600][线段树][替罪羊树]没有人的算术
- [置顶] 3600: 没有人的算术
- bzoj 3600: 没有人的算术 替罪羊树
- BZOJ 3600 没有人的算术
- [bzoj3600]没有人的算术
- bzoj 3600 - 没有人的算术
- bzoj3600 没有人的算术
- bzoj 3600: 没有人的算术 (替罪羊树)
- 【题解】BZOJ 3600: 没有人的算术——替罪羊树、线段树
- [bzoj3600]没有人的算术 替罪羊树+线段树
- [BZOJ3600]没有人的算术 重量平衡树+线段树
- bzoj3600: 没有人的算术