洛谷 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> struct Segment { int l,r,mid,lm,rm,m,lcol,rcol; Segment * ch[2]; Segment () { ch[0]=ch[1]=NULL; lcol=rcol=lm=rm=m=0; } }; int n,m; int max(int a,int b) {return a>b?a:b;} void pushup(Segment *&k) { if(k->l==k->r) return; k->lcol=k->ch[0]->lcol; k->rcol=k->ch[1]->rcol; k->lm=k->ch[0]->lm; k->rm=k->ch[1]->rm; k->m=max(k->ch[0]->m,max(k->ch[1]->m,max(k->ch[0]->rm,k->ch[1]->lm))); if(k->ch[0]->rcol!=k->ch[1]->lcol) { k->m=max(k->m,k->ch[0]->rm+k->ch[1]->lm); if(k->ch[0]->lm==(k->ch[0]->r-k->ch[0]->l+1)) k->lm+=k->ch[1]->lm; if(k->ch[1]->rm==k->ch[1]->r-k->ch[1]->l+1) k->rm+=k->ch[0]->rm; } } void build(Segment *&k,int l,int r) { k=new Segment; k->l=l;k->r=r; if(l==r) {k->lcol=k->rcol=0;k->lm=k->rm=k->m=1;return;} k->mid=l+r>>1; build(k->ch[0],l,k->mid); build(k->ch[1],k->mid+1,r); pushup(k); } void modify(Segment *&k,int t) { if(k->l==k->r) { k->lcol=k->rcol^=1; return; } if(t<=k->mid) modify(k->ch[0],t); else modify(k->ch[1],t); pushup(k); } int Main() { Segment * root=new Segment; scanf("%d%d",&n,&m); build(root,1,n); for(int x;m--;) { scanf("%d",&x); modify(root,x); printf("%d\n",root->m); } return 0; } int sb=Main(); int main(int argc,char *argv[]) {;}
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。