线段树杭电ojTunnel Warfare

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树杭电ojTunnel Warfare相关的知识,希望对你有一定的参考价值。

  • 博客主页: https://blog.csdn.net/qq_50285142
  • 欢迎点赞👍收藏✨关注❤留言 📝 如有错误,敬请指正
  • 🎈虽然生活很难,但我们也要一直走下去🎈

题目链接

题意:
有一排村庄,村庄两两之间有一条地道,可以进行三种操作:
1.D摧毁一座村庄(村庄毁了,与它连接的地道也毁了)
2.Q询问一座村庄连接的村庄数目(地道必须连接)
3.R恢复上一次摧毁的村庄

思路:
【线段树】
我们考虑把村庄按节点来存储,存储两个属性,区间最大值和区间最小值
把区间最大值初始化为0,区间最小值初始化为n+1

为何要维护最大最小值呢?
摧毁一座村庄时,把此处的值改为相应的下标。
比如:3和5被摧毁了
村庄:1 2 3 4 5 6 7
mx : 8 8 3 8 5 8 8
mn : 0 0 3 0 5 0 0
4村庄能够联通的村庄数为 [ 4 , n ] [4,n] [4,n]中的最小值 − [ 1 , 4 ] -[1,4] [1,4]中的最大值 − 1 -1 1
所以我们通过维护被摧毁村庄的最大最小值来计算村庄能联通的村庄数。
但是存在一个特例,就是如果查询的村庄已经被毁,查到的最大最小值相等,需要进行特判

初始值为n+1和0是考虑到如果一个村庄的后面都没有被毁掉,那么找出来的最小值为n+1,可看作是最后一个村庄的后面一位,避免忽略掉第n个村庄
初始值为0也是一样的道理

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
const int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const int mod = 1e9+7;
const int N = 5e4+5,M = 2e5+5;

int n,m,k;

int sta[N],cur;
struct node
{
	int l,r;
	ll mx,mn;
}tr[N*4];

void pushup(int u)
{
	tr[u].mx = max(tr[u<<1].mx,tr[u<<1|1].mx);
	tr[u].mn = min(tr[u<<1].mn,tr[u<<1|1].mn);
}
void build(int u,int l,int r)
{
	tr[u] = {l,r};
	if(l==r)
	{
		tr[u].mx = 0;
		tr[u].mn = n+1;
		return ;
	}
	int mid = l + r >> 1;
	build(u<<1,l,mid),build(u<<1|1,mid+1,r);
	pushup(u);
}

void modify(int u,int x,int y,int z)
{
	if(tr[u].l==x and tr[u].r==x) 
	{
		tr[u].mn = y;
		tr[u].mx = z;
		return ;
	}
	int mid = tr[u].l + tr[u].r >> 1;
	if(x <= mid) modify(u<<1,x,y,z);
	else modify(u<<1|1,x,y,z);
	pushup(u);
}

ll query_max(int u,int l,int r)
{
	if(tr[u].l >= l and tr[u].r <= r) return tr[u].mx;
	else
	{
		int mid = tr[u].l + tr[u].r >> 1;
		ll mx = 0;
		if(l <= mid) mx = query_max(u<<1,l,r);
		if(r > mid) mx = max(mx,query_max(u<<1|1,l,r));
		return mx;
	}
}
ll query_min(int u,int l,int r)
{
	if(tr[u].l >= l and tr[u].r <= r) return tr[u].mn;
	else
	{
		int mid = tr[u].l + tr[u].r >> 1;
		ll mn = inf;
		if(l <= mid) mn = query_min(u<<1,l,r);
		if(r > mid) mn = min(mn,query_min(u<<1|1,l,r));
		return mn;
	}
}
void solve()
{
	while(~scanf("%d%d",&n,&m))
	{
		build(1,1,n);
		while(m--)
		{
			char s[2];
			scanf("%s",s);
			if(*s=='D')
			{
				int x;scanf("%d",&x);
				sta[++cur] = x;
				modify(1,x,x,x); 
			}
			else if(*s=='Q') 
			{
				int x;scanf("%d",&x);
				int mn = query_min(1,x,n);
				int mx = query_max(1,1,x);
				if(mx==mn) printf("0\\n");
				else printf("%d\\n",mn-mx-1);
			}
			else
			{
				int x = sta[cur--];
				modify(1,x,n+1,0);
			}
		}
	}
}
int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0),cout.tie(0);
	int _;
//	cin>>_;
	_ = 1;
	while(_--)
	{
		solve();
	}
	return 0;
}


往期优质文章推荐

以上是关于线段树杭电ojTunnel Warfare的主要内容,如果未能解决你的问题,请参考以下文章

HDU 1540 Tunnel Warfare (线段树或set水过)

Tunnel Warfare HDU - 1540(线段树最长连续区间)

poj 2892 Tunnel Warfare(线段树)

hdu1540 Tunnel Warfare 线段树/树状数组

Tunnel Warfare 线段树 区间合并|最大最小值

hdu--1540 Tunnel Warfare(线段树+区间合并)