【30.01%】【hdu 3397】Sequence operation
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7822 Accepted Submission(s): 2347
We have five operations here:
Change operations:
0 a b change all characters into '0's in [a , b]
1 a b change all characters into '1's in [a , b]
2 a b change all '0's into '1's and change all '1's into '0's in [a, b]
Output operations:
3 a b output the number of '1's in [a, b]
4 a b output the length of the longest continuous '1' string in [a , b]
Each case has two integers in the first line: n and m (1 <= n , m <= 100000).
The next line contains n characters, '0' or '1' separated by spaces.
Then m lines are the operations:
op a b: 0 <= op <= 4 , 0 <= a <= b < n.
1
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
5
2
6
5
【题解】
给你个01串。
有以下几种操作:
1.把[l.r]区间的所有数都置为0或1.
2.把[l,r]区间的所有数都置为其相反数.
3.求[l,r]区间内的1的个数.
4.求[l,r]区间内的最长的连续的'1'的个数.
求[l..r]区间内的1的个数,实际上就是对l..r这个区间求和.(只有0和1)
然后求l..r区间内的最长的连续的'1'的个数则需要一些技巧。
这样想。
一个区间l..r
把它分为左半部分l..m
和右半部分m+1..r
这个最长的所求序列。要么在左边。要么在右边。
要么有一部分在左边有一部分在右边。
于是我们设lx[rt]表示rt这个区间内的最长所求序列的长度;
则lx[rt] = max{lx[rt<<1],lx[rt<<1|1]};
然后对于横跨左右两边的情况。
我们需要记录lnum[rt],rnum[rt],表示这个区间最左边的数字和这个区间最右边的数字。
同时还要记录llx[rt],rlx[rt],表示从区间的最左边的一个端点数起一共有多少个连续的1,以及从区间的最右边的一个端点数起一共有多少个连续的1.
如果rnum[rt<<1] == lnum[rt<<1|1] == 1;
则lx[rt]还有多一种更新即lx[rt] = max{lx[rt],rlx[rt<<1]+llx[rt<<1|1]};
但这还远远不够我们在进行取反操作之后重新更新这些值。
想想如果我们对一个区间取反了。要怎么重新确定llx[rt],rlx[rt],lx[rt]这些值???
0->1
1->0
启发我们可以多开一个域。记录有关0的连续序列的信息
即llx[0..1][rt],rlx[0..1][rt],lx[0..1][rt];
则我们取反之后swap(llx[1][rt],llx[0][rt])swap(rlx[1][rt] , rlx[0][rt])swap(lx[1][rt] , lx[0][rt]);
即有关0的连续的信息,有关1的连续的信息同时记录下来。
sum的话就直接等于len-sum了
具体的看代码;
处理区间的时候,左右端点都递增了1,这样就是1-n了不是0到n-1
【代码】
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson begin,m,rt<<1
#define rson m+1,end,rt<<1|1 using namespace std; const int MAXN = 100100; int n, m;
int llx[2][MAXN * 4], rlx[2][MAXN * 4], lx[2][MAXN * 4];
int sum[MAXN * 4], qufan[MAXN * 4], fugai[MAXN * 4],lnum[MAXN*4],rnum[MAXN*4]; void push_up(int rt, int len)
{
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
for (int ii = 0; ii <= 1; ii++)//0和1的信息都要维护
{
bool flag = false;
if (rnum[rt << 1] == ii && lnum[rt << 1 | 1] == ii)
flag = true;
lx[ii][rt] = max(lx[ii][rt << 1], lx[ii][rt << 1 | 1]);
if (flag)
lx[ii][rt] = max(lx[ii][rt], rlx[ii][rt << 1] + llx[ii][rt << 1 | 1]);
llx[ii][rt] = llx[ii][rt << 1];
if (llx[ii][rt] == (len - (len >> 1)) && flag)//如果左区间都是一样的数字
llx[ii][rt] += llx[ii][rt << 1 | 1];//加上右区间的左半部分
rlx[ii][rt] = rlx[ii][rt << 1 | 1];
if (rlx[ii][rt] == len >> 1 && flag )
rlx[ii][rt] += rlx[ii][rt << 1];
}
lnum[rt] = lnum[rt << 1];
rnum[rt] = rnum[rt << 1 | 1];
} void build(int begin, int end, int rt)
{
if (begin == end)
{
int x;
scanf("%d", &x);
for (int ii = 0; ii <= 1; ii++)
if (x == ii)
llx[ii][rt] = rlx[ii][rt] = lx[ii][rt] = 1;
else
llx[ii][rt] = rlx[ii][rt] = lx[ii][rt] = 0;
if (x == 0)
sum[rt] = 0, lnum[rt] = 0, rnum[rt] = 0;
else
sum[rt] = 1,lnum[rt] =1,rnum[rt] = 1;
return;
}
int m = (begin + end) >> 1;
build(lson);
build(rson);
push_up(rt,end-begin+1);
} void input_data()
{
scanf("%d%d", &n, &m);
build(1, n, 1);
} void init()//初始化
{
memset(fugai, 255, sizeof(fugai));
memset(qufan, 0, sizeof(qufan));
memset(llx, 0, sizeof(llx));
memset(sum, 0, sizeof(sum));
memset(rlx, 0, sizeof(rlx));
memset(lx, 0, sizeof(lx));
} void tihuan(int rt, int len, int num)//把rt这个节点全部替换为num
{
sum[rt] = len*num;
lnum[rt] = rnum[rt] = num;
for (int ii = 0; ii <= 1; ii++)
if (num == ii)
llx[ii][rt] = rlx[ii][rt] = lx[ii][rt] = len;
else
llx[ii][rt] = rlx[ii][rt] = lx[ii][rt] = 0;
} void change(int rt, int len) //把rt这个区间全部取反
{
swap(lx[0][rt], lx[1][rt]);
swap(llx[0][rt], llx[1][rt]);
swap(rlx[0][rt], rlx[1][rt]);
sum[rt] = len - sum[rt];
lnum[rt] = 1 - lnum[rt];
rnum[rt] = 1 - rnum[rt];
} void pre_change(int rt,int len)//把rt区间取反
{
if (fugai[rt] != -1)
{
fugai[rt] = 1 - fugai[rt];
tihuan(rt, len, fugai[rt]);
}
else
{
qufan[rt] = 1 - qufan[rt];
change(rt, len);
}
} void push_down(int rt, int len)
{
if (fugai[rt] != -1)
{
fugai[rt << 1] = fugai[rt << 1 | 1] = fugai[rt];
qufan[rt << 1] = qufan[rt << 1 | 1] = 0;
tihuan(rt << 1, len - (len >> 1), fugai[rt]);
tihuan(rt << 1 | 1, len >> 1, fugai[rt]);
fugai[rt] = -1;
}
else //如果有覆盖操作就不可能有取反操作(想想为什么)
if (qufan[rt]!=0)
{
pre_change(rt << 1, len - (len >> 1));
pre_change(rt << 1 | 1, len >> 1);
qufan[rt] = 0;
}
} void up_data(int op, int l, int r, int begin, int end, int rt)
{
if (l <= begin && end <= r)
{
if (op <= 1) //覆盖操作
{
fugai[rt] = op;
qufan[rt] = 0;
tihuan(rt, end - begin + 1,op);
}
else //取反操作
pre_change(rt, end - begin + 1);
return;
}
push_down(rt, end - begin + 1);
int m = (begin + end) >> 1;
if (l <= m)
up_data(op, l, r, lson);
if (m < r)
up_data(op, l, r, rson);
push_up(rt, end - begin + 1);
} int query_sum(int l, int r, int begin, int end, int rt)//求和
{
if (l <= begin && end <= r)
return sum[rt];
int dd = 0;
push_down(rt,end-begin+1);
int m = (begin + end) >> 1;
if (l <= m)
dd += query_sum(l, r, lson);
if (m < r)
dd += query_sum(l, r, rson);
return dd;
} int query_lx(int l, int r, int begin, int end, int rt)//寻找最长连续1
{
if (l <= begin && end <= r)
return lx[1][rt];
push_down(rt, end - begin + 1);
int dd = 0;
int m = (begin + end) >> 1;
bool flag1 = false, flag2 = false;
if (l <= m)
{
dd = max(dd, query_lx(l, r, lson));
flag1 = true;
}
if (m < r)
{
dd = max(dd, query_lx(l, r, rson));
flag2 = true;
}
//在左边,在右边,横跨中间
if (flag1 && flag2 && rnum[rt << 1] == 1 && lnum[rt << 1 | 1] == 1)
{
int temp1 = min(m - l + 1, rlx[1][rt << 1]);
int temp2 = min(r - m, llx[1][rt << 1 | 1]);
dd = max(dd, temp1 + temp2);
}
return dd;
} void output_ans()
{
for (int i = 1; i <= m; i++)
{
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
x++; y++;
if (op <= 2)
up_data(op, x, y, 1, n, 1);
else
if (op == 3)
printf("%d\n", query_sum(x, y, 1, n, 1));
else
if (op == 4)
printf("%d\n", query_lx(x, y, 1, n, 1));
}
} int main()
{
// freopen("F:\\rush.txt", "r", stdin);
//freopen("F:\\rush_out.txt", "w", stdut);
int t;
scanf("%d", &t);
while (t--)
{
init();
input_data();
output_ans();
}
return 0;
}
【30.01%】【hdu 3397】Sequence operation的更多相关文章
- 【改革春风吹满地 HDU - 2036 】【计算几何-----利用叉积计算多边形的面积】
利用叉积计算多边形的面积 我们都知道计算三角形的面积时可以用两个邻边对应向量积(叉积)的绝对值的一半表示,那么同样,对于多边形,我们可以以多边形上的一个点为源点,作过该点并且过多边形其他点中的某一个的 ...
- 【黑金教程笔记之002】【建模篇】【Lab 01 永远的流水灯】—笔记&勘误
学习并行操作的思想. 勘误001: Page 17,模块图下方,“扫描频配置定为100Hz”应为10Hz. 勘误002: Page 17,最后一行 “10ms”应为100ms:“2.5ms”应为25m ...
- 【转】从外行的视角尝试讲解为什么这回丰田栽了【全文完】【v1.01】
转自:http://club.tgfcer.com/thread-6817371-1-1.html [第一部分]背景简介 前几年闹得沸沸扬扬的丰田刹不住事件最近又有新进展.十月底俄克拉荷马的一次庭审 ...
- hdu 动态规划(46道题目)倾情奉献~ 【只提供思路与状态转移方程】(转)
HDU 动态规划(46道题目)倾情奉献~ [只提供思路与状态转移方程] Robberies http://acm.hdu.edu.cn/showproblem.php?pid=2955 背包 ...
- zw版【转发·台湾nvp系列Delphi例程】HALCON HWindowX 01
zw版[转发·台湾nvp系列Delphi例程]HALCON HWindowX 01 procedure TForm1.Button1Click(Sender: TObject);var img : H ...
- 【HDU 2255】奔小康赚大钱 (最佳二分匹配KM算法)
奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- 【二分】【最长上升子序列】HDU 5489 Removed Interval (2015 ACM/ICPC Asia Regional Hefei Online)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5489 题目大意: 一个N(N<=100000)个数的序列,要从中去掉相邻的L个数(去掉整个区间 ...
- 【贪心】【模拟】HDU 5491 The Next (2015 ACM/ICPC Asia Regional Hefei Online)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5491 题目大意: 一个数D(0<=D<231),求比D大的第一个满足:二进制下1个个数在 ...
- 【动态规划】【二分】【最长上升子序列】HDU 5773 The All-purpose Zero
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5773 题目大意: T组数据,n个数(n<=100000),求最长上升子序列长度(0可以替代任何 ...
随机推荐
- python ddt 实现数据驱动
ddt 是第三方模块,需安装, pip install ddt DDT包含类的装饰器ddt和两个方法装饰器data(直接输入测试数据) 通常情况下,data中的数据按照一个参数传递给测试用例,如果da ...
- Directx11教程(7) 画一个颜色立方体
原文:Directx11教程(7) 画一个颜色立方体 前面教程我们通过D3D11画了一个三角形,本章我们将画一个颜色立方体,它的立体感更强.主要的变动是ModelClass类,在Model ...
- css面试题总结(转)
转自此网页http://www.cnblogs.com/YangqinCao/p/5721810.html. 1.两栏布局,左边栏宽度固定,适应父元素高度变化 首先分析两栏布局, 两栏布局两种常见方法 ...
- linux CentOs 7.4 64位 系统下 nuxt部署 、nginx 安装、node环境及软连接,pm2软连接
一.nginx安装 1.安装依赖包 //一键安装上面四个依赖 yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel 2 ...
- 【JZOJ4845】【NOIP2016提高A组集训第5场11.2】寻找
题目描述 "我有个愿望,我希望穿越一切找到你." 这是个二维平面世界,平面上有n个特殊的果实,我从(0,0)点出发,希望得到尽量多的果实,但是出于某种特殊的原因,我的运动方式只有三 ...
- hdu2149 巴什博奕
n表示先手胜 p表示先手负 1~N N+1 N+2~2*N+1 2*N+2 2*N+3~3*N+2 ... n p n p n ... m总归个数 每次取1~N个根据前面的规律得到,如果m/N==m% ...
- Java排序需掌握算法 详解
package com.sxt.review; /*内部排序:(在内存) * 插入排序-->希尔排序 * 冒泡排序-->快速排序 * 选择排序-->堆排序 * 归并排序 * 基数排序 ...
- 实用的cmd命令
1.打开iis服务器:inetmgr 2.远程连接:mstsc 3.注册表:regedit.exe
- oracle获取中文出现乱码问题解决
首先搞清楚字符集和字符编码概念,了解oracle字符集原理,请参考一位大神的讲解: ref:http://blog.csdn.net/dbanote/article/details/9158367#c ...
- myeclipse2013在线安装svn
之前安装svn一直不行.弄了好久.还是在线安装方便. 在Help里面点击Install from Site,然后直接图解: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkb ...