Vijos P1881 闪烁的繁星

P1881闪烁的繁星

背景

繁星闪烁着--深蓝的太空
何曾听得见他们对语
沉默中
微光里
他们深深的互相颂赞了

描述

繁星, 漫天的繁星.
繁星排成一列, 我数一数呀, 一共有N只小星星呢.

星星们是听话的好孩子, 小岛在指挥它们跳舞呢.
舞蹈开始前, 它们都亮了起来!

小岛指一指第i只小星星, 只见第i只小星星立刻改变了自己的状态.
如果它之前是亮着的, 那么立刻就灭掉了.
如果它之前是灭掉的, 现在就立刻亮了呀!

如果说, 可以有连续若干只小星星.
其中任意相邻两只星星状态不同.
那就是最美的了.

小岛希望知道:
每一次发出指令之后
能找到最长的连续小星星, 满足上述需求的
有多长?

格式

输入格式

第一行有两个整数, 分别为星星总数N, 和指令总数Q.
1<=N<=200,000; 1<=Q<=200,000.
之后Q行, 每行有一个整数i: 1<=i<=N, 表示小岛发出的指令.

输出格式

输出有Q行, 其中每i行有一个整数.
表示小岛的第i条指令发出之后, 可以找到的满足要求的最长连续星星序列有多长?

样例1

样例输入1[复制]

6 2
2
4

样例输出1[复制]

3
5

限制

对于20%的数据: N, Q <= 100.
对于30%的数据: N, Q <= 70000.
对于100%的数据: 1 <= N, Q <= 200,000.

提示

对于样例, 星星序列的状态依次为: OOOOOO -> OXOOOO -> OXOXOO
这里用O表示亮着的星星, 用X表示灭掉的星星.


///更新了下 :放错题了⊙﹏⊙b汗

//这是岛姐的题,线段树都放到第一道了 ⊙﹏⊙b汗

这道题的重点在于PushUp()


#include<iostream>
#include<cstdio>
#include<cstring>
#define MAXN 200000
using namespace std;
struct tree
{
	int l,r;
	int lx,mx,rx; 
}t[MAXN*4];
int n,q;
int a[MAXN];


void init()
{
	freopen("P1881闪烁的繁星.in","r",stdin);
	freopen("P1881闪烁的繁星.out","w",stdout);
}
void PushUp(int u)
{
	/*
	if(t[u<<1].y!=t[u<<1|1].x)
	{
		t[u].len=t[u<<1].len+t[u<<1|1].len;
		return;
	}
	else
	{
		t[u].len=max(t[u<<1].len,t[u<<1|1].len);
		return; 
	}
	*/
	int len=t[u].r-t[u].l+1;
	int mid=(t[u].l+t[u].r)>>1;
    t[u].lx=t[u<<1].lx;
    t[u].rx=t[u<<1|1].rx;
    if(a[mid]!=a[mid+1])
	{
        t[u].mx=max(max(t[u<<1].mx,t[u<<1|1].mx),t[u<<1].rx+t[u<<1|1].lx);
        if(t[u].lx==len-(len>>1))
			t[u].lx+=t[u<<1|1].lx;
        if(t[u].rx==len>>1)
			t[u].rx+=t[u<<1].rx;
    }
	else 
		t[u].mx=max(t[u<<1].mx,t[u<<1|1].mx);
}

void Build(int u,int l,int r)
{
	t[u].l=l;t[u].r=r;
	if(t[u].l==t[u].r)
	{
		t[u].mx=1;
		t[u].lx=1;
		t[u].rx=1;
		return;
	}
	int mid=(t[u].l+t[u].r)>>1;
	Build(u<<1,l,mid);
	Build(u<<1|1,mid+1,r);
	PushUp(u);
}

void Updata(int u,int x)
{
	if(t[u].l==t[u].r)
	{
		a[x]^=1;
		return;
	}
	int mid=(t[u].l+t[u].r)>>1;
	if(x<=mid)	Updata(u<<1,x);
	if(x>mid)	Updata(u<<1|1,x);
	PushUp(u);
}

int main()
{
	init();
	cin>>n>>q;
	Build(1,1,n);
	int x;
	for(int i=1;i<=q;i++)
	{
		scanf("%d",&x);
		Updata(1,x);
		printf("%d\n",t[1].mx);
	}
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值