zoukankan      html  css  js  c++  java
  • 洛谷 P2253 好一个一中腰鼓! 题解

    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温馨提示:其实数据根本没你想象的那么大。。。[坏笑]、、

    【思路】

    线段树
    第一次做不是用来区间求和和区间修改的线段树题目
    窝太菜了

    【题目大意】

    一个0串,可以被翻转为1,同理1也可以翻转为0
    每一次翻转一个位置
    然后求这时候最长的连续的一排同学,满足每相邻的两个手中的腰鼓朝向观众的一面互不相同

    【题目分析】

    Huangc温馨提示:其实数据根本没你想象的那么大。。。[坏笑]、、
    所以跑暴力试一下
    第一个点WA,80分QWQ
    或许是我写丑了
    看题目我是想不到要用线段树的,毕竟之前没有做过这一类的题目
    但是洛谷标签提醒了我
    所以要用线段树
    单点修改很容易
    那就难在求最长序列
    可以记录某个线段l,r和mi
    l表示在这个线段中以左端点为起点的最长合法序列的长度
    r表示在这个线段中以右端点为重点的最长合法序列的长度
    mi就是这个线段中最长的合法序列长度了

    【核心思路】

    需要处理处每个线段里面的l,r和mi

    k的l至少是等于他左儿子的l的,因为k线段的左端点等于他左儿子的左端点
    然后这个时候在看看连接了右儿子之后l会不会增加
    不过会增加也是有个前提条件的就是左儿子这一块全部合法才能够连到右儿子上面
    判断右儿子和左儿子交界处是否不同
    不同的话就将l+右儿子的l

    k的r至少是他右儿子的r,理由和上面类似
    让再判断连接了左儿子之后r会不会增加
    这个也是有前提条件的就是右儿子全部合法不然碰不到左儿子

    k的mi是他两个儿子的mi的最大值
    但是有可能这个最长合法序列的左右端点都不是左右边界
    那就是在中间的情况
    所以在和左儿子的r和右儿子的l也就是左右儿子交界的地方那里存在的最长合法序列
    输出最大值就好了

    【完整代码】

    #include<iostream>
    #include<cstdio>
    #define lson (k << 1)
    #define rson (k << 1 | 1)
    using namespace std;
    
    int read()
    {
    	int sum = 0,fg = 1;
    	char c = getchar();
    	while(c < '0' || c > '9')
    	{
    		if(c == '-')fg = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9')
    	{
    		sum = sum * 10 + c - '0';
    		c = getchar();
    	}
    	return sum * fg;
    }
    const int Max = 20004;
    struct node
    {
    	int l;//区间内以左端点为起点的合法区间长度 
    	int mi;//区间内合法区间最长的 
    	int r;//区间内以右端点为终点的合法区间的长度 
    }a[Max << 2];
    int opx;
    int use[Max];//记录当前情况 
    
    void down(int k,int l,int r,int mid)
    {
    	a[k].l = a[lson].l;
    	if(use[mid] != use[mid + 1] && mid - l + 1 == a[lson].l)
    		a[k].l += a[rson].l;
    	a[k].r = a[rson].r;
    	if(use[mid] != use[mid + 1] && r - mid == a[rson].r)
    		a[k].r += a[lson].r;
    	a[k].mi = max(a[lson].mi,a[rson].mi);
    	if(use[mid] != use[mid + 1])
    		a[k].mi = max(a[k].mi,a[lson].r + a[rson].l);
    	return;
    }
    
    void change(int k,int l,int r)
    {
    	if(l == opx && r == opx)
    	{
    		if(use[opx] == 1)
    			use[opx] = 0;
    		else
    			use[opx] = 1;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(opx <= mid)change(lson,l,mid);
    	if(opx > mid)change(rson,mid + 1,r);
    	down(k,l,r,mid);
    }
    
    void build(int k,int l,int r)
    {
    	if(l == r)
    	{
    		a[k].l = 1;
    		a[k].r = 1;
    		a[k].mi = 1;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(lson,l,mid);
    	build(rson,mid + 1,r);
    	down(k,l,r,mid);
    }
    
    int main()
    {
    	int n = read(),m = read();
    	build(1,1,n);
    	for(register int i = 1;i <= m;++ i)
    	{
    		opx = read();
    		change(1,1,n);
    		cout << max(a[1].mi,max(a[1].l,a[1].r)) << endl; 
    	}
    	return 0;
    } 
    
  • 相关阅读:
    爬取校园新闻首页的新闻的详情,使用正则表达式,函数抽离
    网络爬虫基础练习
    Mysql 使用 select into outfile
    Mysql 使用CMD 登陆
    使用Clean() 去掉由函数自动生成的字符串中的双引号
    Get Resultset from Oracle Stored procedure
    获取引用某个主键的所有外键的表
    Entity Framework 丢失数据链接的绑定,在已绑好的EDMX中提示“Choose Your Data Connection”
    添加MySql Metat Database 信息
    at System.Data.EntityClient.EntityConnection.GetFactory(String providerString)
  • 原文地址:https://www.cnblogs.com/acioi/p/11838799.html
Copyright © 2011-2022 走看看