HDU 1540 - Tunnel Warfare (set|线段树)

题目

题意:

给你n个村庄,他们按照顺序连在一起,有3种操作。

D X,摧毁X,所以它两边的边也没了。

R,恢复最近一次摧毁的村庄

Q X,问你x村庄向左向右,一共连了多少个村庄。

题目没说清楚的地方:

(1)多case

(2)某个村庄可以被毁坏多次(必须全部入栈),但只需要一次就能将其恢复(下面的这组数据,,)

(3)D 3 D 2 D 1 D 1 D 2

//R 恢复2

//R 恢复1

//R 恢复3

1.用set做。把摧毁的村庄加入set,然后二分查找x,找到前一个和后一个,做差即可。为了方便可以把0和n+1放入set。

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stack>
#include <set>
using namespace std;
#define LL long long
set<int> st;
stack<int> q;
set<int> ::iterator it;
int vis[100000];
int main()
{
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		st.clear();
		memset(vis,0,sizeof vis);
		while(!q.empty()) q.pop();
		st.insert(0);
		st.insert(n+1);
		for(int i=1;i<=m;i++){
			char c;
			cin>>c;
			if(c=='D') {
				int x;scanf("%d",&x);
				q.push(x);
				st.insert(x);
				vis[x]=1;
			}else if(c=='R'){
				while(!q.empty()&&vis[q.top()]==0){
					q.pop();
				}
				if(!q.empty()){
					st.erase(st.lower_bound(q.top()));
					vis[q.top()]=0;
					q.pop();
				}
			}else{
				int x;scanf("%d",&x);
				it=st.lower_bound(x);
				if(*it==x){
					printf("0\n");
				}else{
					printf("%d\n",*it-*(--it)-1);
				}
			}
		}
	}

}

2.常规的线段树写。

每一个区间保存L,R。L代表左端点向右有几个连续的村庄。R同理。

难点在于查询。query(x)代表查询x村庄。

如果这个区间l==r或者整个区间都有村庄连续着(R[x]==r-l+1) 那么直接返回。

若x在左子树,那么看看左子树的R[lt]包不包含x,若包含:

就还要查询右子树即(query(mid+1)) 查询右子树的最左端点在【区间内】有多少连续的。

同理。x在右子树也一样。

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stack>
using namespace std;
#define LL long long
#define lt x<<1
#define rt x<<1|1
const int maxn = 100000+33;
stack<int> q;
int L[maxn<<2],R[maxn<<2];

void update(int x,int l,int r)
{
	L[x]=L[lt];
	R[x]=R[rt];
	int mid = (l+r)>>1;
	if(L[lt]==mid-l+1) L[x]+=L[rt];
	if(R[rt]==r-mid) R[x]+=R[lt];
}

void build(int x,int l,int r)
{
	if(l==r){
		L[x]=R[x]=1;
	}else{
		int mid = (l+r)>>1;
		build(lt,l,mid);
		build(rt,mid+1,r);
		update(x,l,r);
	}
}

void change(int x,int l,int r,int pos,int p)
{
	if(l==r){
		L[x]=R[x]=p;
	}else{
		int mid = (l+r)>>1;
		if(pos<=mid) change(lt,l,mid,pos,p);
		else change(rt,mid+1,r,pos,p);
		update(x, l, r);
	}
}

int query(int x,int l,int r,int pos)
{
	if(l==r||r-l+1==R[x]){
		return R[x];
	}else{
		int mid = (l+r)>>1;
		if(pos<=mid){
			if(pos>=mid-R[lt]+1){
				return query(lt,l,mid,pos)+query(rt,mid+1,r,mid+1);
			}else
				return query(lt,l,mid,pos);
		}else{
			if(pos<=mid+L[rt])
				return query(lt,l,mid,mid)+query(rt,mid+1,r,pos);
			else
				return query(rt,mid+1,r,pos);
		}
	}
}


int vis[100000];

int main()
{
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		memset(vis,0,sizeof vis);
		while(!q.empty()) q.pop();
		build(1, 1, n);
		for(int i=1;i<=m;i++){
			char c;
			cin>>c;
			if(c=='D') {
				int x;scanf("%d",&x);
				q.push(x);
				change(1,1,n,x,0);
				vis[x]=1;
			}else if(c=='R'){
				while(!q.empty()&&vis[q.top()]==0){
					q.pop();
				}
				if(!q.empty()){
					change(1,1,n,q.top(),1);
					vis[q.top()]=0;
					q.pop();
				}
			}else{
				int x;scanf("%d",&x);
				printf("%d\n",query(1,1,n,x));
			}
		}
	}

}

猜你喜欢

转载自blog.csdn.net/mr_treeeee/article/details/81139684