HDU1540 Tunnel Warfare【线段树区间合并、平衡树】

题目链接

题意

有一段连续的序列 [ 1 , 2 , 3 , . . . , n ] [1,2,3,...,n] [1,2,3,...,n],有3种操作

  1. 删除数字 K K K K K K的两边断开
  2. 询问数字 K K K 所在的连续段的长度(若 K K K被删除则长度为0)
  3. 回撤上一次删除操作

题解

有两种做法

  1. 线段树区间合并,记录区间的最长左连续段长度和最长右连续段长度
  2. 平衡树记录删除的结点,询问的答案就是 K K K后继-前驱-1
#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<vector>
#include<stack>
#include <utility>
#include<list>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<time.h>
#include<random>
using namespace std;
#include<ext/pb_ds/priority_queue.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
#include<ext/rope>
using namespace __gnu_cxx;

#define int long long
#define PI acos(-1.0)
#define eps 1e-9
#define lowbit(a) ((a)&-(a))

const int mod = 1e9+7;
int qpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=(ans*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ans;
}
const int INF = 0x3f3f3f3f;
const int N = 2e5+10;
struct node{
	int l,r,mid;
	int llen,rlen;
}seg[N];

void pushup(int rt){
	seg[rt].llen=seg[rt<<1].llen+(seg[rt<<1].llen==seg[rt<<1].r-seg[rt<<1].l+1?seg[rt<<1|1].llen:0);
	seg[rt].rlen=seg[rt<<1|1].rlen+(seg[rt<<1|1].rlen==seg[rt<<1|1].r-seg[rt<<1|1].l+1?seg[rt<<1].rlen:0);
}
void build(int rt,int l,int r){
	int mid=l+r>>1;	
	seg[rt].l=l,seg[rt].mid=mid,seg[rt].r=r,seg[rt].llen=1,seg[rt].rlen=1;
	if(l==r)return ;
	build(rt<<1,l,mid),build(rt<<1|1,mid+1,r);
	pushup(rt);
}
void update(int rt,int pos,int val){
	if(seg[rt].l==seg[rt].r){ seg[rt].llen=seg[rt].rlen=val; return ; }
    update(rt<<1|(pos>seg[rt].mid),pos,val);
    pushup(rt);
}
int query(int rt,int pos){ 
    if(seg[rt].l==seg[rt].r) return seg[rt].llen;
    if(pos<=seg[rt].mid){ 
        if (pos>=seg[rt<<1].r-seg[rt<<1].rlen+1) return seg[rt<<1].rlen+seg[rt<<1|1].llen;
        return query(rt<<1,pos);
    }
    else{
        if(pos<=seg[rt<<1|1].l+seg[rt<<1|1].llen-1) return seg[rt<<1|1].llen+seg[rt<<1].rlen;
        return query(rt<<1|1,pos);
    }
}
#define endl '\n'
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int n,q;
	while(cin>>n>>q){
		stack<int>sk; while(!sk.empty()) sk.pop();
		build(1,1,n);
		while(q--){
			string s; cin>>s;
			if(s=="D"){ int p; cin>>p; update(1,p,0); sk.push(p); }
			if(s=="R"){ update(1,sk.top(),1); sk.pop(); }
			if(s=="Q"){ int p; cin>>p; cout<<query(1,p)<<endl; }
		}
	}
}

(有现成的set不会有人手写平衡树吧

#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<vector>
#include<stack>
#include <utility>
#include<list>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<time.h>
#include<random>
using namespace std;
#include<ext/pb_ds/priority_queue.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
#include<ext/rope>
using namespace __gnu_cxx;

#define int long long
#define PI acos(-1.0)
#define eps 1e-9
#define lowbit(a) ((a)&-(a))

const int mod = 1e9+7;
int qpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=(ans*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ans;
}
const int INF = 0x3f3f3f3f;
const int N = 1e6+10;

#define endl '\n'
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int n,q; 
	while(cin>>n>>q){
		set<int>st;
		stack<int>s;
		st.insert(0);
		st.insert(n+1);
		for(int i=1;i<=q;i++){
			char op; int k; cin>>op;
			if(op=='D')cin>>k,st.insert(k),s.push(k);
			if(op=='Q'){
				cin>>k;
				if(st.find(k)!=st.end())cout<<0<<endl;
				else{
					auto l=st.lower_bound(k),r=st.lower_bound(k);
					cout<<*r-*--l-1<<endl;
				}
			}
			if(op=='R')st.erase(s.top()),s.pop();
		}
	}
	
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值