Tunnel Warfare(最大连续子段和)

HDOJ 1540

题意:输入n,m表示n个村庄和m次操作。
后面m行,有3种操作:

  • D x:第x个村庄被毁。
  • Q x:指挥官询问第x个村庄与其直接或间接相关的村庄数量。
  • R:最后毁坏的村庄被重建了。

方法一

分析:本来是线段树练习题,但是我第一眼看真的是STL裸题,用set就能解决。

#include <iostream>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <set>
#include <cstdio>
#include <algorithm>
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const int mod=1e9+7;
const int maxn=5e4+10;
ll n,m; 

int main() {

	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	while (cin>>n>>m) {
		char tag;
		set <ll> s;
		stack <ll> k;
		set <ll> :: iterator it;
		ll last;
		while (m--) {
			cin>>tag;			
			if (tag=='D') {
				cin>>last;
				s.insert(last);
				k.push(last);
			} 
			else if (tag=='Q') {
				cin>>last;
				if (s.count(last)) {
					cout<<"0"<<endl;
					continue;
				}
				it=s.upper_bound(last);
				ll t=*it;
				//cout<<t<<endl;			
				if (it!=s.end()) {
					if (it!=s.begin()){
						it--;
						cout<<t-*it-1<<endl;
					}
					else {
						cout<<t-1<<endl;
					}
				}
				else {
					if (s.empty()) cout<<n<<endl;
					else {
						it=s.end();
						it--;
						cout<<n-*it<<endl;
					}
				}
			} 
			else {
				last=k.top();
				k.pop();
				s.erase(last);
			}
				
		}
	}
	return 0;
}

方法二

分析:线段树维护最大连续子段和

#include <iostream>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <set>
#include <cstdio>
#include <algorithm>
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const int mod=1e9+7;
const int maxn=5e4+10;

struct Node {
	ll ms,ls,rs;
} tree[maxn<<2];

ll n,m;

void push_up(ll p, ll l, ll r){
	ll lson=p<<1;
	ll rson=(p<<1)|1;
	ll m=(l+r)>>1;
	tree[p].ls=tree[lson].ls;
	tree[p].rs=tree[rson].rs;
	//左子树 ls = 区间,则加上 右子树 ls 
	if (tree[lson].ls==m-l+1) tree[p].ls+=tree[rson].ls;
	//右子树 rs = 区间,则加上 左子树 rs 
	if (tree[rson].rs==r-m) tree[p].rs+=tree[lson].rs;
	tree[p].ms=max(max(tree[lson].ms,tree[rson].ms),tree[lson].rs+tree[rson].ls);
}


void build(ll p, ll l, ll r){
	if (l==r){
		tree[p].ls=tree[p].rs=tree[p].ms=1;
		return;
	} 
	ll m=(l+r)>>1;
	build(p<<1,l,m),build((p<<1)|1,m+1,r);
	push_up(p,l,r);
}

void update(ll p, ll x, ll z, ll l, ll r) {
	if (l==r) {
		tree[p].ls=tree[p].rs=tree[p].ms=z;
		return;
	}
	ll m=(l+r)>>1;
	if (x<=m) update(p<<1,x,z,l,m);
	else update((p<<1)|1,x,z,m+1,r);
	push_up(p,l,r);
}

ll query(ll p, ll x, ll s, ll t) {
	if (s==t || tree[p].ms==0) return tree[p].ms;
	ll m=(s+t)>>1;
	if (x<=m){
		// x 在左子树 rs 的区间中, 则与右子树 ls 相连
		if (m-x+1<=tree[p<<1].rs)
			return tree[p<<1].rs+tree[(p<<1)|1].ls;
		else return query(p<<1,x,s,m);
		//如果x不在这个区间,说明x还在左边,继续查询
	}
	else {
		// x 在右子树 ls 的区间中,则与左子树 rs 相连
		if (x-m<=tree[(p<<1)|1].ls)
			return tree[p<<1].rs+tree[(p<<1)|1].ls;
		else return query((p<<1)|1,x,m+1,t);
		//如果x不在这个区间,说明x还在右边,继续查询
	} 
		
}


int main() {

	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	while (cin>>n>>m) {
		char tag;
		build(1,1,n);
		ll last;
		stack <ll> k;
		while (m--) {
			cin>>tag;
			if (tag=='D') {
				cin>>last;
				k.push(last);
				update(1,last,0,1,n);
			} 
			else if (tag=='Q') {
				cin>>last;
				cout<<query(1,last,1,n)<<endl;
			} 
			else {
				last=k.top();
				k.pop();
				update(1,last,1,1,n);
			}
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值