惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
云风的 BLOG
云风的 BLOG
人人都是产品经理
人人都是产品经理
T
The Blog of Author Tim Ferriss
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
J
Java Code Geeks
博客园 - 聂微东
B
Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
WordPress大学
WordPress大学
腾讯CDC
L
LangChain Blog
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Azure Blog
Microsoft Azure Blog
D
DataBreaches.Net
The GitHub Blog
The GitHub Blog
美团技术团队
博客园 - Franky
Google DeepMind News
Google DeepMind News
V
V2EX
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
The Cloudflare Blog

博客园 - 糖豆爸爸

【树上DP前导知识汇总】 快速幂、龟速乘总结 反向建图+拓扑排序 卡特兰数专题(Catalan) AcWing 126. 最大的和 AcWing 431. 守望者的逃离 AcWing 414. 数字游戏 AcWing 468. 魔法阵 AcWing 463. 求和 洛谷 P1632 点的移动 P1056 NOIP2008 普及组 排座椅 洛谷 P1889 士兵站队 洛谷 P1862 输油管道问题 CF444C DZY Loves Colors SCOI2010 P2572 序列操作 P4344 SHOI2015 脑洞治疗仪 T125847 【模板】动态开点线段树 P3373 【模板】线段树 2 Physical Education Lessons
P2253 好一个一中腰鼓!
糖豆爸爸 · 2023-09-05 · via 博客园 - 糖豆爸爸

\(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 <bits/stdc++.h>
using namespace std;
const int N = 20010;

// 线段树
#define mid ((l + r) >> 1)
#define ls (u << 1)
#define rs (u << 1 | 1)
struct Node {
    int l, r, len;
    int lx, rx, mx; // lx:左起最长符合条件的长度;rx:右起最长符合条件的长度;mx:整体区间内符合条件的长度
} tr[N << 2];

int color[N]; // 每个位置上的颜色

void pushup(int u) {
    // 左儿子的最右端点颜色,与右儿子的最左端点颜色是否相同
    bool flag = color[tr[ls].r] != color[tr[rs].l];

    tr[u].lx = tr[ls].lx; // 左起最长,继承左儿子的左起最长
    // 如果左儿子全部区间满足条件,并且,左儿子最右,不等于,右儿子最左,也就是继续符合条件
    if ((tr[ls].lx == tr[ls].len) && flag) tr[u].lx = tr[ls].len + tr[rs].lx;

    tr[u].rx = tr[rs].rx; // 右起最长,继承右儿子的右起最长
    // 如果右儿子全部区间满足条件,并且,右儿子最左,不等于,左儿子最右,也就是继续符合条件
    if ((tr[rs].rx == tr[rs].len) && flag) tr[u].rx = tr[rs].len + tr[ls].rx;

    tr[u].mx = max(tr[ls].mx, tr[rs].mx);
    if (flag) tr[u].mx = max(tr[u].mx, tr[ls].rx + tr[rs].lx); // 拼接
}

void build(int u, int l, int r) {
    tr[u].l = l, tr[u].r = r, tr[u].len = r - l + 1;

    if (l == r) {
        tr[u].lx = tr[u].rx = tr[u].mx = 1; // 表演刚开始每一个鼓都是红色面朝向观众
        return;
    }
    build(ls, l, mid);
    build(rs, mid + 1, r);
    pushup(u);
}

void modify(int u, int p) {
    int l = tr[u].l, r = tr[u].r;
    if (l == r) {
        color[p] = !color[p]; // 红变白,白变红
        return;
    }
    if (p <= mid)
        modify(ls, p);
    else
        modify(rs, p);
    pushup(u);
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("P2253.in", "r", stdin);
#endif
    int n, m;
    cin >> n >> m;

    build(1, 1, n);

    while (m--) {
        int p;
        cin >> p;
        modify(1, p);
        printf("%d\n", tr[1].mx);
    }
    return 0;
}