平衡二叉树SBT||线段树区间维护poj2892
2014-07-07 16:11
267 查看
题意:有第三种操作:
D x表示毁掉村庄x;
Q x表示询问x在内的最大连续的村庄;
R表示重建最近被毁掉的村庄
思路:用一个栈存储被毁掉的村庄,以便修复。开一个访问数组,如果村庄被毁掉则标记,查询的时候直接输出0;
然后线段树维护连续的村庄。
现在用SBT重写一遍。
树中保存已经被摧毁的村庄,查询的时候只需要找到x的前驱跟后继,相减再减一就是区间长度
D x表示毁掉村庄x;
Q x表示询问x在内的最大连续的村庄;
R表示重建最近被毁掉的村庄
思路:用一个栈存储被毁掉的村庄,以便修复。开一个访问数组,如果村庄被毁掉则标记,查询的时候直接输出0;
然后线段树维护连续的村庄。
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> using namespace std; const int maxn=50010; int n,m; bool vis[maxn]; stack<int> s; struct IntervalTree { int ls[maxn<<3],rs[maxn<<3]; void maintain(int o,int l,int r) { ls[o]=ls[o<<1],rs[o]=rs[o<<1|1]; int mid=(l+r)>>1; if(ls[o]==mid-l+1)ls[o]+=ls[o<<1|1]; if(rs[o]==r-mid)rs[o]+=rs[o<<1]; } void build(int o,int l,int r) { ls[o]=rs[o]=0; if(l==r) { ls[o]=rs[o]=1; return; } int mid=(l+r)>>1; build(o<<1,l,mid); build(o<<1|1,mid+1,r); maintain(o,l,r); } void update(int o,int l,int r,int pos,int x) { if(l==r) { ls[o]+=x; rs[o]+=x; return ; } int mid=(l+r)>>1; if(pos<=mid)update(o<<1,l,mid,pos,x); else update(o<<1|1,mid+1,r,pos,x); maintain(o,l,r); } int query(int o,int l,int r,int pos)//注意一下如何查询 { int ans=0; if(l==r)return 1; int mid=(l+r)>>1; if(pos<=mid) { if(pos>=mid-rs[o<<1]+1)return query(o<<1,l,mid,pos)+ls[o<<1|1];//如果在连续的那一段则要加上右孩子右面连续的一段; else return query(o<<1,l,mid,pos); } else { if(pos<=mid+ls[o<<1|1])return query(o<<1|1,mid+1,r,pos)+rs[o<<1]; return query(o<<1|1,mid+1,r,pos); } } }tree; int main() { //freopen("in.txt","r",stdin); char op[5]; int x; scanf("%d%d",&n,&m); tree.build(1,1,n); memset(vis,0,sizeof(vis)); while(m--) { scanf("%s",op); if(op[0]=='D') { scanf("%d",&x); vis[x]=1; tree.update(1,1,n,x,-1); s.push(x); } else if(op[0]=='Q') { scanf("%d",&x); if(vis[x])printf("0\n"); else printf("%d\n",tree.query(1,1,n,x)); } else { x=s.top();s.pop(); vis[x]=0; tree.update(1,1,n,x,1); } } return 0; }
现在用SBT重写一遍。
树中保存已经被摧毁的村庄,查询的时候只需要找到x的前驱跟后继,相减再减一就是区间长度
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> using namespace std; const int maxn=50010; int vis[maxn]; int N,M; stack<int> st; int root,tot; void init() { while(!st.empty())st.pop(); memset(vis,0,sizeof(vis)); root=tot=0; } struct SBT { int left,right,size,key; void init(int val) { left=right=0; key=val; size=1; } }tree[maxn]; void left_rotate(int &x) { int y=tree[x].right; tree[x].right=tree[y].left; tree[y].left=x; tree[y].size=tree[x].size; tree[x].size=tree[tree[x].left].size+tree[tree[x].right].size+1; x=y; } void right_rotate(int &x) { int y=tree[x].left; tree[x].left=tree[y].right; tree[y].right=x; tree[y].size=tree[x].size; tree[x].size=tree[tree[x].left].size+tree[tree[x].right].size+1; x=y; } void maintain(int &x,int flag) { if(!flag) { if(tree[tree[tree[x].left].left].size>tree[tree[x].right].size) right_rotate(x); else if(tree[tree[tree[x].left].right].size>tree[tree[x].right].size) left_rotate(tree[x].left),right_rotate(x); else return; } else { if(tree[tree[tree[x].right].right].size>tree[tree[x].left].size) left_rotate(x); else if(tree[tree[tree[x].right].left].size>tree[tree[x].left].size) right_rotate(tree[x].right),left_rotate(x); else return; } maintain(tree[x].left,0); maintain(tree[x].right,1); maintain(x,0); maintain(x,1); } //插入值为key的节点 void insert(int &x,int key) { if(!x) { x=++tot; tree[x].init(key); } else { tree[x].size++; if(key<tree[x].key)insert(tree[x].left,key); else insert(tree[x].right,key); maintain(x,key>=tree[x].key); } } int del(int &x,int key) { if(!x)return 0; tree[x].size--; if(key==tree[x].key||(key<tree[x].key&&tree[x].left==0)|| (key>tree[x].key&&tree[x].right==0)) { if(tree[x].left&&tree[x].right) { int p=del(tree[x].left,key+1); tree[x].key=tree[p].key; return p; } else { int p=x; x=tree[x].left+tree[x].right; return p; } } else return del(key<tree[x].key?tree[x].left:tree[x].right,key); } //返回值v的前驱的值,如果没有前驱返回v本身 int Pred(int t,int v) { if(!t)return v; if(v<=tree[t].key)return Pred(tree[t].left,v); else { int tmp=Pred(tree[t].right,v); return v==tmp?tree[t].key:tmp; } } //返回值v的后继的值,如果没有后继返回v本身 int Succ(int t,int v) { if(!t)return v; if(v>=tree[t].key)return Succ(tree[t].right,v); else { int tmp=Succ(tree[t].left,v); return v==tmp?tree[t].key:tmp; } } int main() { char op[5]; int x; while(scanf("%d%d",&N,&M)!=EOF) { init(); while(M--) { scanf("%s",op); if(op[0]=='D') { scanf("%d",&x); //if(vis[x])continue; vis[x]++; st.push(x); insert(root,x); } else if(op[0]=='R') { if(!st.empty()) { del(root,st.top()); vis[st.top()]--; if(vis[st.top()]<=0)st.pop(); } } else { scanf("%d",&x); if(vis[x])printf("0\n"); else { int r=Succ(root,x); if(r==x)r=N+1; int l=Pred(root,x); if(l==x)l=0; printf("%d\n",r-l-1); } } } } return 0; }
相关文章推荐
- HDU5091->线段树维护区间覆盖次数&&扫描线
- HDU 6070 Dirt Ratio 分数规划 二分 线段树维护区间最值
- codevs 1082 线段树练习 3(区间维护)
- hdu 3397 Sequence Operation 线段树维护区间前后缀和,求子区间连续最值
- 东东的高速之旅 (线段树维护区间最小值)(模拟赛)
- LuoguP2846[USACO08NOV]光开关Light Switching【线段树维护区间异或】By cellur925
- hdoj1754 I Hate It【线段树区间最大值维护+单点更新】
- 【bzoj1593-预定旅馆】线段树维护连续区间
- hdu 1540 Tunnel Warfare (线段树维护左右最长连续区间)
- 【hdu5381】维护区间内所有子区间的gcd之和-线段树
- POJ-3468-A Simple Problem with Integers(线段树区间维护 重写Lazy)
- 51nod-1376(线段树维护区间最值)
- 【不定期更新】线段树写过的区间维护
- Codevs-4919 线段树练习4(区间加上一个值并求摸个区间整除k的数的个数,线段树+数组维护)
- gym101138J(树链剖分,线段树维护区间连续子段最大和,好题)
- POJ 2182 Lost Cows 题解 (线段树维护区间变化or暴力)
- 一道线段树维护区间操作的题 soj4234 01Pairs
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
- 【线段树维护区间编号 && 区间更新】HDU - 4614 Vases and Flowers
- HUST1722(线段树维护区间最大连续和)