hdu1540 poj2892 Tunnel Warfare 线段树端点更新 SBT
2014-08-13 19:14
417 查看
题目大意,给n个点表示n个村庄,一开始都是相连的,现在有3种操作:Q x,查询第与第x个村庄相连的村庄个数;D x,摧毁掉第x个村庄;R 恢复刚摧毁的村庄。
题目分析:每个点用2个状态表示,0表示被摧毁,1表示存在,因为有恢复操作,并且每次恢复上一个被摧毁的村庄,所以用一个栈存储所有被摧毁的村庄,每次R操作恢复栈顶村庄。这题关键是查询操作,如果查询的村庄x不存在,则没有村庄与之相连通,如果存在x村庄,那么从x往2边找连续的存在的村庄。如何找这个连续的存在的村庄。
自顶向下找,如果找到左边第一个不存在的村庄,找到右边第一个不存在的村庄,相减即可。
SBT版,比poj多了一个坑点,就是同一个城市可以删多次,对于线段树无所谓,可对于SBT来说会造成多个相同值的插入。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <stack>
#include <algorithm>
using namespace std;
#define maxn 510000
int n,m,l,r,root,cnt,val[maxn],ls[maxn],rs[maxn],siz[maxn];
bool vis[maxn];
void rotate_r(int &x)
{
int y=ls[x];
siz[y]=siz[x];
ls[x]=rs[y];
rs[y]=x;
siz[x]=siz[ls[x]]+siz[rs[x]]+1;
x=y;
}
void rotate_l(int &x)
{
int y=rs[x];
siz[y]=siz[x];
rs[x]=ls[y];
ls[y]=x;
siz[x]=siz[ls[x]]+siz[rs[x]]+1;
x=y;
}
void maintain(int& x,int fg)
{
if(!fg)
{
if(siz[ls[ls[x]]]>siz[rs[x]]) rotate_r(x);
else if(siz[rs[ls[x]]]>siz[rs[x]]) rotate_l(ls[x]),rotate_r(x);
else return ;
}
else
{
if(siz[rs[rs[x]]]>siz[ls[x]]) rotate_l(x);
else if(siz[ls[rs[x]]]>siz[ls[x]]) rotate_r(rs[x]),rotate_l(x);
else return ;
}
maintain(ls[x],0);maintain(rs[x],1);
maintain(x,0);maintain(x,1);
}
void insert(int& x,int b)
{
if(!x)
{
cnt++;
x=cnt;
ls[x]=rs[x]=0;
siz[x]=1;
val[x]=b;
}
else
{
siz[x]++;
if(b>val[x]) insert(rs[x],b);
else insert(ls[x],b);
maintain(x,b>=val[x]);
}
}
int delt(int& x,int b)
{
siz[x]--;
if(b==val[x]||(b<val[x]&&ls[x]==0)||(b>val[x]&&rs[x]==0))
{
int y=val[x];
if(!ls[x]||!rs[x]) x=ls[x]+rs[x];
else val[x]=delt(ls[x],b+1);
return y;
}
else
{
if(b<val[x]) return delt(ls[x],b);
else return delt(rs[x],b);
}
}
int pred(int&x ,int y,int b)
{
if(!x) return y;
if(val[x]<b) return pred(rs[x],x,b);
return pred(ls[x],y,b);
}
int succ(int&x ,int y,int b)
{
if(!x) return y;
if(val[x]>b) return succ(ls[x],x,b);
return succ(rs[x],y,b);
}
void sbt()
{
root=cnt=0;
memset(ls,0,sizeof(ls));
memset(rs,0,sizeof(rs));
memset(siz,0,sizeof(siz));
memset(vis,0,sizeof(vis));
memset(val,0,sizeof(val));
insert(root,0);
insert(root,n+1);
int op,a,b,f;
char str[10];
stack<int>st;
for(int i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='D')
{
scanf("%d",&b);
if(!vis[b]) insert(root,b);
st.push(b);
vis[b]=true;
}
else if(str[0]=='Q')
{
scanf("%d",&b);
if(vis[b])
{
printf("0\n");
continue;
}
int f1=pred(root,0,b);
int f2=succ(root,0,b);
printf("%d\n",val[f2]-val[f1]-1);
}
else
{
delt(root,st.top());
vis[st.top()]=false;
st.pop();
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
sbt();
}
return 0;
}
题目分析:每个点用2个状态表示,0表示被摧毁,1表示存在,因为有恢复操作,并且每次恢复上一个被摧毁的村庄,所以用一个栈存储所有被摧毁的村庄,每次R操作恢复栈顶村庄。这题关键是查询操作,如果查询的村庄x不存在,则没有村庄与之相连通,如果存在x村庄,那么从x往2边找连续的存在的村庄。如何找这个连续的存在的村庄。
自顶向下找,如果找到左边第一个不存在的村庄,找到右边第一个不存在的村庄,相减即可。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> using namespace std; #define maxn 50005 #define lson rt<<1 , l , m #define rson rt<<1|1 , m+1 , r int tree[maxn<<2],leaf[maxn],n; void build(int rt,int l,int r) { if(l==r) { tree[rt]=1; leaf[l]=rt; return; } int m=(l+r)>>1; build(lson); build(rson); tree[rt]=tree[rt<<1]+tree[rt<<1|1]; } void update(int rt,int l,int r,int x,int val) { if(l==r) { tree[rt]=val; return ; } int m=(l+r)>>1; if(x<=m) update(lson,x,val); else update(rson,x,val); if(tree[rt<<1]==(m-l+1)&&tree[rt<<1|1]==r-m) tree[rt]=r-l+1; else tree[rt]=0; } int query(int rt,int l,int r,int x,int dir) { int m=(l+r)>>1; if(x<1||x>n) { return x; } if(tree[rt]==r-l+1) { if(dir) { return query(1,1,n,r+1,dir); } else { return query(1,1,n,l-1,dir); } } if(l==r) { return l; } if(x<=m) return query(lson,x,dir); else return query(rson,x,dir); } int main() { char op[5]; int m,a,b,c,x,y,z; while(~scanf("%d%d",&n,&m)) { stack<int>st; build(1,1,n); for(int i=1;i<=m;i++) { scanf("%s",op); if(op[0]=='R') { int num=st.top(); st.pop(); update(1,1,n,num,1); } else { scanf("%d",&x); if(op[0]=='D') { st.push(x); update(1,1,n,x,0); } else { int ans = tree[leaf[x]]; if(ans == 0) printf("0\n"); else { ans=1; if(x<n) { ans+=query(1,1,n,x+1,1)-x-1; } if(x>1) { ans+=x-query(1,1,n,x-1,0)-1; } printf("%d\n",ans); } } } } } return 0; }
SBT版,比poj多了一个坑点,就是同一个城市可以删多次,对于线段树无所谓,可对于SBT来说会造成多个相同值的插入。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <stack>
#include <algorithm>
using namespace std;
#define maxn 510000
int n,m,l,r,root,cnt,val[maxn],ls[maxn],rs[maxn],siz[maxn];
bool vis[maxn];
void rotate_r(int &x)
{
int y=ls[x];
siz[y]=siz[x];
ls[x]=rs[y];
rs[y]=x;
siz[x]=siz[ls[x]]+siz[rs[x]]+1;
x=y;
}
void rotate_l(int &x)
{
int y=rs[x];
siz[y]=siz[x];
rs[x]=ls[y];
ls[y]=x;
siz[x]=siz[ls[x]]+siz[rs[x]]+1;
x=y;
}
void maintain(int& x,int fg)
{
if(!fg)
{
if(siz[ls[ls[x]]]>siz[rs[x]]) rotate_r(x);
else if(siz[rs[ls[x]]]>siz[rs[x]]) rotate_l(ls[x]),rotate_r(x);
else return ;
}
else
{
if(siz[rs[rs[x]]]>siz[ls[x]]) rotate_l(x);
else if(siz[ls[rs[x]]]>siz[ls[x]]) rotate_r(rs[x]),rotate_l(x);
else return ;
}
maintain(ls[x],0);maintain(rs[x],1);
maintain(x,0);maintain(x,1);
}
void insert(int& x,int b)
{
if(!x)
{
cnt++;
x=cnt;
ls[x]=rs[x]=0;
siz[x]=1;
val[x]=b;
}
else
{
siz[x]++;
if(b>val[x]) insert(rs[x],b);
else insert(ls[x],b);
maintain(x,b>=val[x]);
}
}
int delt(int& x,int b)
{
siz[x]--;
if(b==val[x]||(b<val[x]&&ls[x]==0)||(b>val[x]&&rs[x]==0))
{
int y=val[x];
if(!ls[x]||!rs[x]) x=ls[x]+rs[x];
else val[x]=delt(ls[x],b+1);
return y;
}
else
{
if(b<val[x]) return delt(ls[x],b);
else return delt(rs[x],b);
}
}
int pred(int&x ,int y,int b)
{
if(!x) return y;
if(val[x]<b) return pred(rs[x],x,b);
return pred(ls[x],y,b);
}
int succ(int&x ,int y,int b)
{
if(!x) return y;
if(val[x]>b) return succ(ls[x],x,b);
return succ(rs[x],y,b);
}
void sbt()
{
root=cnt=0;
memset(ls,0,sizeof(ls));
memset(rs,0,sizeof(rs));
memset(siz,0,sizeof(siz));
memset(vis,0,sizeof(vis));
memset(val,0,sizeof(val));
insert(root,0);
insert(root,n+1);
int op,a,b,f;
char str[10];
stack<int>st;
for(int i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='D')
{
scanf("%d",&b);
if(!vis[b]) insert(root,b);
st.push(b);
vis[b]=true;
}
else if(str[0]=='Q')
{
scanf("%d",&b);
if(vis[b])
{
printf("0\n");
continue;
}
int f1=pred(root,0,b);
int f2=succ(root,0,b);
printf("%d\n",val[f2]-val[f1]-1);
}
else
{
delt(root,st.top());
vis[st.top()]=false;
st.pop();
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
sbt();
}
return 0;
}
相关文章推荐
- HDU 1540——Tunnel Warfare(线段树,区间合并+单点更新+单点查询)
- hdu 1540 Tunnel Warfare 线段树 单点更新,查询区间长度,区间合并
- HDU 1540 Tunnel Warfare(线段树 区间合并 +单点更新)
- HDU - 1540Tunnel Warfare(线段树 单点更新 区间查询)
- hdu 1540 Tunnel Warfare 线段树 单点更新,查询区间长度,区间合并
- HDU-1540 Tunnel Warfare (线段树 维护端点信息)
- 【HDU - 1540】Tunnel Warfare 【线段树+单点更新+区间合并】
- POJ 2892 Tunnel Warfare || HDU 1540(树状数组+二分 || 线段树的单点更新+区间查询)
- HDU 1540 Tunnel Warfare(线段树单点更新+区间合并)
- hdu 1540 Tunnel Warfare(线段树单点更新+区间合并)
- HDU 1540 && POJ 2892 Tunnel Warfare (线段树,区间合并).
- hdu 1540 & poj 2892 Tunnel Warfare 线段树区间合并
- 【HDU】 1540 Tunnel Warfare 线段树
- hdu 1540 Tunnel Warfare(线段树区间统计)
- hdu-1540-Tunnel Warfare-线段树
- HDU 1540 Tunnel Warfare(线段树)
- 【Hdu】1540 Tunnel Warfare(线段树|区间合并)
- hdu 1540 Tunnel Warfare【线段树】
- hdu 1540 Tunnel Warfare (线段树维护左右最长连续区间)
- hdu 1540 Tunnel Warfare(单点更新,区间合并)