洛谷P2253 好一个一中腰鼓!

题目背景

话说我大一中的运动会就要来了,据本班同学剧透(其实早就知道了),我萌萌的初二年将要表演腰鼓[喷],这个无厘头的题目便由此而来。

Ivan乱入:“忽一人大呼:‘好一个安塞腰鼓!’满座寂然,无敢哗者,遂与外人间隔。”

题目描述

设想一下,腰鼓有两面,一面是红色的,一面是白色的。初二的苏大学神想给你这个oier出一道题。假设一共有N(1<=N<=20,000)个同学表演,表演刚开始每一个鼓都是红色面朝向观众,舞蹈老师会发出M(1<=M<=20,000)个指令,如果指令发给第i个表演的同学,这位同学就会把腰鼓反过来,如果腰鼓之前是红色面朝向观众的,那么就会变成白色面朝向观众,反之亦然。那么问题来了(!?),在老师每一次发出指令后,找到最长的连续的一排同学,满足每相邻的两个手中的腰鼓朝向观众的一面互不相同,输出这样一排连续的同学的人数。

输入输出格式

输入格式:

 

第一行有两个整数, 分别为表演的同学总数N, 和指令总数M。

之后M行, 每行有一个整数i: 1<=i<=N, 表示舞蹈老师发出的指令。

 

输出格式:

 

输出有M行, 其中每i行有一个整数.

表示老师的第i条指令发出之后, 可以找到的满足要求的最长连续的一排表演同学有多长?

 

输入输出样例

输入样例#1:
6 2
2
4
输出样例#1:
3
5

说明

Huangc温馨提示:其实数据根本没你想象的那么大。。。[坏笑]、、

分析:一类线段树的经典题型,这种题和求最长相同颜色区间的做法是差不多的,都是要用线段树解决,那么要记录哪些信息呢?满足要求的区间长度是肯定要记录的,还要记录每一个区间左端点和右端点的颜色,仅仅用这些信息还不能更新区间长度,还要记录每个区间从左向右最多能扩展多少,从右向左能扩展多少,这样就能求出答案来。

      合并是一个难点,当前区间的答案可能是左区间的答案也可能是右区间的答案也可能是左右中间合并的答案,在合并的时候判断一下左右端点的颜色是否相同就好了.同时还要更新向右延伸的最大长度和向左延伸的最大长度.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

int n,m,lnum[200010],rnum[200010],lc[200010],rc[200010],ans[200010];

void pushup(int o,int len)
{
    lnum[o] = lnum[o * 2];
    rnum[o] = rnum[o * 2 + 1];
    lc[o] = lc[o * 2];
    rc[o] = rc[o * 2 + 1];
    ans[o] = max(max(lnum[o * 2],max(rnum[o * 2 + 1],max(rnum[o * 2],lnum[o * 2 + 1]))),max(ans[o * 2],ans[o * 2 + 1]));
    if (rc[o * 2] != lc[o * 2 + 1])
    {
        ans[o] = max(ans[o],rnum[o * 2] + lnum[o * 2 + 1]);
        if (lnum[o * 2] == (len - (len >> 1)))
        lnum[o] += lnum[o * 2 + 1];
        if (rnum[o * 2 + 1] == (len >> 1))
        rnum[o] += rnum[o * 2];
    }
}

void build(int l,int r,int o)
{
    if (l == r)
    {
        lnum[o] = rnum[o] = ans[o] = 1;
        lc[o] = rc[o] = 0;
        return;
    }
    int mid = (l + r) >> 1;
    build(l,mid,o * 2);
    build(mid + 1,r,o * 2 + 1);
    pushup(o,r - l + 1);
}

void update(int l,int r,int o,int v)
{
    if (l == r)
    {
        lc[o] = rc[o] = (lc[o] + 1) % 2;
        return;
    }
    int mid = (l + r) >> 1;
    if (v <= mid)
    update(l,mid,o * 2,v);
    else
    update(mid + 1,r,o * 2 + 1,v);
    pushup(o,r - l + 1);
}

int main()
{
    scanf("%d%d",&n,&m);
    build(1,n,1);
    for (int i = 1; i <= m; i++)
    {
        int t;
        scanf("%d",&t);
        update(1,n,1,t);
        printf("%d\n",ans[1]);
    }

    return 0;
}

 

posted @ 2017-09-10 16:25 zbtrs 阅读(...) 评论(...) 编辑 收藏