HDU 1540 Tunnel Warfare(线段树维护最大连续区间长度)
题目大意:
一段长为n的区间,m此操作,Q为查询x所在区间的最大长度,D为将X破坏(不连通),R为将最后一个破坏的点修复(连通)。
题解思路:
线段树,维护3个值。
1.区间前缀长度
2.区间后缀长度
3.区间里最长连续区间
用栈存储一下破坏的点,线段树的更新维护写在代码里;
10001111 前缀为1 后缀为4;。
维护前缀和后缀,是为了在归并和查询过程中维护连续区间长度。
对于 0 0 0 1 1 1 1 1 0 1在归并中连续区间长度应为lson的后缀+rson的前缀
在维护父节点前缀(后缀)时优先继承左孩子前缀(右孩子后缀),如果左孩子前缀(右孩子后缀)的长度等于区间长度应再加上右孩子前缀(左孩子后缀)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<algorithm>
//被模板题搞自闭的蒟蒻
#define lson rt<<1
#define rson rt<<1|1
const int maxn=1e5+10;
using namespace std;
struct node{
int ls,rs,sum;
}tree[4*maxn];
//ls 前缀 rs 后缀 sum连续区间长度
int n,m;
void built(int l,int r,int rt)
{
int mid=(r+l)/2,sum=r-l+1;
tree[rt]=(node){sum,sum,sum};
if(l==r)
return ;
built(l,mid,lson);
built(mid+1,r,rson);
}
void updata(int l,int r,int rt,int aim,int val)
{
if(l==r)
{
tree[rt].ls=tree[rt].rs=tree[rt].sum=val;
return ;
}
int mid=(l+r)>>1;
if(aim<=mid)
{
updata(l,mid,lson,aim,val);
}
if(aim>mid)
{
updata(mid+1,r,rson,aim,val);
}
tree[rt].ls=tree[lson].ls;//父节点继承左孩子的前缀
tree[rt].rs=tree[rson].rs;
if(tree[lson].ls==mid-l+1)//如果左孩子的前缀等于区间长度(左孩子满了)
tree[rt].ls+=tree[rson].ls;//加上右孩子的前缀
if(tree[rson].rs==r-mid)
tree[rt].rs+=tree[lson].rs;
tree[rt].sum=max(max(tree[lson].sum,tree[rson].sum),tree[lson].rs+tree[rson].ls);
//父节点的sum为 左右孩子的最大值 与 左右孩子连起来的区间区最大值
// 例如:110111 100111
}
int query(int l,int r,int rt,int aim)
{
if(l==r||tree[rt].sum==0||tree[rt].sum==l-r+1)
{//如果到了叶子节点或者区间值等于0或区间长度直接返回即可
return tree[rt].sum;
}
int mid=(l+r)>>1;
if(aim<=mid)
{
if(aim>=mid-tree[lson].rs+1)
//如果查询点在左孩子的后缀中
//查询左孩子的长度加上右孩子的前缀
//例如 0 0 0 1 1 1 1 1 0 1
// x
return query(l,mid,lson,aim)+tree[rson].ls;
else
//否则只查询左孩子
return query(l,mid,lson,aim);
}
else
{
if(aim<=mid+tree[rson].ls)
//(mid+1)+tree[rson]-1
//同上
// 1 1 1 0 1 1 1 1 0 1
// x
return query(mid+1,r,rson,aim)+tree[lson].rs;
else
return query(mid+1,r,rson,aim);
}
}
int main(){
while(~scanf("%d%d",&n,&m))
{
built(1,n,1);
stack<int>q;
while(m--)
{
char s[5];
int now;
scanf("%s",s);
if(s[0]=='R')
{
if(q.size())
{
updata(1,n,1,q.top(),1);
q.pop();
}
}
if(s[0]=='D')
{
scanf("%d",&now);
q.push(now);
updata(1,n,1,now,0);
}
if(s[0]=='Q')
{
scanf("%d",&now);
printf("%d\n",query(1,n,1,now));
}
}
}
return 0;
}