[Tunnel Warfare] [HDU

[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
";
				continue;
			}
			int l=*(--s.upper_bound(k));
			int r=*(s.upper_bound(k));
			Prin(r-l-1);
			puts("");
		}
	}	
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Suki-Sugar/p/15139691.html