[Tunnel Warfare] [HDU - 1540] T4 D3
[Tunnel Warfare] [HDU - 1540]( Problem - 1540 (hdu.edu.cn) ) T4 D3
1.线段树单点修改 、区间合并
思路:
1表示当前村子没被摧毁,0表示摧毁了
llen 表示当前区间左端点向右连续的1的个数
rlen 表示当前区间右端点向左连续的1的个数
用线段树维护 llen, rlen
询问时:
- k在左子树
- 若k在左子树的rlen中,返回左子树的rlen+右子树的llen
- 否则递归左子树
- k在右子树
- 若k在右子树的llen中,返回左子树的rlen+右子树的llen
- 否则递归右子树
参考代码
#include<bits/stdc++.h>
#define ll long long
#define ls (p<<1)
#define rs ((p<<1)|1)
#define mid ((t[p].l+t[p].r)>>1)
using namespace std;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(int x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}
const int qs=1e5+7;
struct Tree{
int l,r,llen,rlen;
#define l(x) t[x].l
#define r(x) t[x].r
#define llen(x) t[x].llen
#define rlen(x) t[x].rlen
}t[qs<<2];
int a[qs],cnt,n,q;
void pushup(int p){
llen(p)=llen(ls)+(llen(ls)==r(ls)-l(ls)+1 ? llen(rs) : 0);
rlen(p)=rlen(rs)+(rlen(rs)==r(rs)-l(rs)+1 ? rlen(ls) : 0);
}
void build(int p,int l,int r){
l(p)=l,r(p)=r;
if(l==r) {
llen(p)=rlen(p)=1;
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(p);
}
void update(int p,int l,int r,int k){
if(l<=l(p)&&r>=r(p)){
llen(p)=rlen(p)=k;
return;
}
if(l<=mid) update(ls,l,r,k);
if(r>mid) update(rs,l,r,k);
pushup(p);
}
int ask(int p,int l,int r){
if(l<=l(p)&&r>=r(p)) return llen(p);
if(l<=mid){
if(l>=r(ls)-rlen(ls)+1) return rlen(ls)+llen(rs);
else return ask(ls,l,r);
}
if(r>mid) {
if(r<=l(rs)+llen(rs)-1) return rlen(ls)+llen(rs);
else return ask(rs,l,r);
}
return 0;
}
int main(){
while(~scanf("%d%d",&n,&q)){
build(1,1,n);
cnt=0;
//getchar();
while(q--){
char c;int k;
cin>>c;
if(c=='R'){
k=a[cnt];
update(1,k,k,1);
cnt--;
continue;
}
k=read();
if(c=='D'){
a[++cnt]=k;
update(1,k,k,0);
}
else{
int ans=ask(1,k,k);
Prin(ans);
puts("");
}
}
}
return 0;
}
2.set+二分
思路:
set时自动排序的(int默认升序),查找一个村庄的情况时,只需要找到这个村庄标号两边被毁的最近的村子。相减即可,查找过程二分。
参考代码
#include<bits/stdc++.h>
#define ll long long
#define ls (p<<1)
#define rs ((p<<1)|1)
#define mid ((t[p].l+t[p].r)>>1)
using namespace std;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(int x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}
const int qs=1e5+7;
int n,cnt,q,a[qs];
int main(){
while(~scanf("%d%d",&n,&q)){
cnt=0;
set<int> s;
s.insert(0),s.insert(n+1);
while(q--){
char c;int k;
cin>>c;
if(c=='R'){
k=a[cnt];
s.erase(k);
cnt--;
continue;
}
k=read();
if(c=='D'){
a[++cnt]=k;
s.insert(k);
}
else{
if(s.find(k)!=s.end()){
cout<<"0\n";
continue;
}
int l=*(--s.upper_bound(k));
int r=*(s.upper_bound(k));
Prin(r-l-1);
puts("");
}
}
}
return 0;
}