Tunnel Warefare(线段树)

  • Tunnel Warefare
  • 题意
    可以理解为开始的时候有一条链,有三种操作:
    1、D n :将链从位置n的地方断开
    2、R : 将上一个断开的位置接上
    3、Q n:包含位置n的最大连续链的长度
  • 题解
    因为是写的线段树的专题,而且看操作明显也是线段树,但是想了好久也没有想明白用线段树维护什么,看了其他大佬的博客才顿悟。
    线段树的节点需要维护三个变量

maxx:该区间内最大的连续链的长度
lmax:从左端点开始往右扩展的最大连续的长度
rmax:从右端点开始往左扩展的最大连续的长度

具体的解释都写在代码中了

#pragma GCC optimize(2)
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
#define pi acos(-1.0)
#define e exp(1.0)
#define pb push_back
#define mk make_pair
#define fir first
#define sec second
#define scf scanf
#define prf printf
typedef pair<ll,ll> pa;
const int dir_4[4][2]={-1,0,0,1,1,0,0,-1};
const int dir_8[8][2]={-1,-1,-1,0,-1,1,0,1,1,1,1,0,1,-1,0,-1};
const ll INF=0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
const int MAX_N=5e4+7;
struct Node{
	int l,r,maxx,lmax,rmax;
	Node(){}
	Node(int l,int r,int maxx,int lmax,int rmax):l(l),r(r),maxx(maxx),lmax(lmax),rmax(rmax){}
	int mid(){
		return (l+r)>>1;
	} 
	int len(){
		return (r-l+1);
	}
	
}node[MAX_N<<2];
void pushup(int rt){
	//maxx;要么是左右儿子的maxx的最大值,或者是左儿子的rmax和右儿子的lmax拼接起来的值 
	node[rt].maxx=max(max(node[rt<<1].maxx,node[rt<<1|1].maxx),node[rt<<1].rmax+node[rt<<1|1].lmax);
	//lmax:如果左儿子包含的整个区间是连续的,那么还得加上右儿子的lmax 
	node[rt].lmax=node[rt<<1].lmax+(node[rt<<1].lmax==node[rt<<1].len()?node[rt<<1|1].lmax:0);
	//rmax:如果右儿子包含的整个区间是连续的,那么还得加上左儿子的rmax 
	node[rt].rmax=node[rt<<1|1].rmax+(node[rt<<1|1].rmax==node[rt<<1|1].len()?node[rt<<1].rmax:0);
	return ;
}
void built_tree(int rt,int l,int r){
	node[rt]=Node(l,r,1,1,1);
	if(l==r)
	return ;
	int m=node[rt].mid();
	built_tree(rt<<1,l,m);
	built_tree(rt<<1|1,m+1,r);
	pushup(rt);//更新父节点 
	return ;
}
void update(int rt,int tar,int var){
	if(node[rt].l==tar&&node[rt].r==tar){
		node[rt]=Node(tar,tar,var,var,var);
		return ;
	}
	int m=node[rt].mid();
	if(tar<=m)
	update(rt<<1,tar,var);
	else
	update(rt<<1|1,tar,var);
	pushup(rt);//修改之后更新 
	return ;
}
int query(int rt,int tar){
	if(!node[rt].maxx||node[rt].l==node[rt].r)
	return node[rt].maxx;//如果函数从这个地方返回的,说明该节点包含的整个区间肯定是连续的 
	int m=node[rt].mid();
	if(tar<=m){
		//如果tar在左儿子rmax包含的区间中,答案还得加上右儿子的lmax 
		if(tar>=node[rt<<1].r-node[rt<<1].rmax+1){
			return node[rt<<1].rmax+node[rt<<1|1].lmax;
		}
		//否则继续找 
		return query(rt<<1,tar);
	}
	else{
		//如果tar在右儿子lmax包含的区间中,答案还得加上左儿子的rmax 
		if(tar<=node[rt<<1|1].l+node[rt<<1|1].lmax-1){
			return node[rt<<1|1].lmax+node[rt<<1].rmax;
		}
		//否则继续找 
		return query(rt<<1|1,tar);
	}
}
int N,M; 
stack<int>st;//用来存储被断开的链点 
int main()
{
//  freopen(".../.txt","w",stdout);
//  freopen(".../.txt","r",stdin);
//	ios::sync_with_stdio(false);
	int i,j,k,n;
	//多组输入。不然WA给你看 
	while(~scf("%d %d",&N,&M)){
		built_tree(1,1,N);
		while(!st.empty())
		st.pop();
		while(M--){
			string s;
			cin>>s;
			if(s[0]=='D'){
				scf("%d",&n);
				st.push(n);
				update(1,n,0);
			}
			else if(s[0]=='Q'){
				scf("%d",&n);
				int res=query(1,n);
				prf("%d\n",res);
			}
			else if(!st.empty()){
				n=st.top();
				st.pop();
				update(1,n,1);
			}
		}
	}
	return 0;
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值