UESTC 1592 An easy problem B 线段树区间合并
来源:互联网 发布:淘宝网络营销 编辑:程序博客网 时间:2024/06/15 03:08
An easy problem B
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)Submit Status
N个数排成一列,每个数的大小为1或者0。有两种操作,第一种操作是把一段区间内的每个数异或1,第二种操作是询问区间内最长连续1的长度。
Input
第一行一个整数N(1≤N≤100000),表示N个数。第二行N个数。接下来一行一个整数M(1≤M≤100000),表示M个操作,接下来M行每行三个整数K,L,R。K=1表示把L到R这段区间的数全部异或上1,K=0表示询问L到R这段区间内最长连续1的长度。
Output
对于每个询问,输出对应的答案,每个询问占一行。Sample input and output
Sample Input Sample Output5
0 1 0 0 1
5
0 1 4
1 1 1
0 1 4
1 3 4
0 1 4
1
2
4
Source
2017 UESTC Training for Data Structures UESTC 1592 An easy problem B
My Solution
题意:区间更新把该区间内所有的数异或1,区间查询该区间内最长连续1的长度。
线段树区间合并
每个节点维护十元组
int summid[4*MAXN][2], suml[4*MAXN][2], sumr[4*MAXN][2], ans[4*MAXN][2], lazy[4*MAXN], rev[4*MAXN];
summid[Ind][k]表示该区间的中间的最长连续k(0|1)的长度,
suml[Ind][k]描述该区间从左端点开始的最长连续k(0|1)的长度,
sumr[Ind][k]表示从该区间右端点结束的最长连续k(0|1)的长度,
ans[Ind][k]表示该区间的最长连续k(0|1)的长度,
lazy[Ind]为延迟操作的标记,
rev[Ind]为旋转(异或)操作的标记。
每次pushup的时候,刷新这十元组,
inline void pushupk(int l, int r, int Ind, int k)
{
int mid = (l + r) >> 1;
if(mid - l + 1 == summid[Ind<<1][k]) suml[Ind][k] = summid[Ind<<1][k] + suml[Ind<<1|1][k];
else suml[Ind][k] = suml[Ind<<1][k];
if(r - (mid+1) + 1 == summid[Ind<<1|1][k]) sumr[Ind][k] = sumr[Ind<<1][k] + summid[Ind<<1|1][k];
else sumr[Ind][k] = sumr[Ind<<1|1][k];
summid[Ind][k] = max(max(summid[Ind<<1][k], summid[Ind<<1|1][k]), sumr[Ind<<1][k] + suml[Ind<<1|1][k]);
ans[Ind][k] = max(max(ans[Ind<<1][k], ans[Ind<<1|1][k]), max(suml[Ind][k], sumr[Ind][k]));
ans[Ind][k] = max(ans[Ind][k], summid[Ind][k]);
}
inline void pushup(int l, int r, int Ind)
{
pushupk(l, r, Ind, 0);
pushupk(l, r, Ind, 1);
}
每次如果有被标记过的延迟标记这pushdown
inline void pushdownk(int Ind)
{
swap(suml[Ind][0], suml[Ind][1]);
swap(sumr[Ind][0], sumr[Ind][1]);
swap(summid[Ind][0], summid[Ind][1]);
swap(ans[Ind][0], ans[Ind][1]);
}
inline void pushdown(int Ind)
{
lazy[Ind<<1] ^= 1;
lazy[Ind<<1|1] ^= 1;
rev[Ind<<1] ^= 1;
rev[Ind<<1|1] ^= 1;
if(rev[Ind<<1]){
pushdownk(Ind<<1);
rev[Ind<<1] ^= 1;
}
if(rev[Ind<<1|1]){
pushdownk(Ind<<1|1);
rev[Ind<<1|1] ^= 1;
}
lazy[Ind] = 0;
}
查询的时候,可以建立5个全局int findans, lans, rans, midans, rl;
每次查询到该最小区间即if(a <= l && r <= b)的时候刷新这个全局的四元组,
这样就不需要给查询函数设定返回值了,写起来比较方便,
即直接对该查询区间分成的子区间进行合并,具体见代码。
复杂度 O(nlogn)
#include <iostream>#include <cstdio>#include <cstring>using namespace std;typedef long long LL;const int MAXN = 1e5 + 8;const int INF = -2e9+8;int summid[4*MAXN][2], suml[4*MAXN][2], sumr[4*MAXN][2], ans[4*MAXN][2], lazy[4*MAXN], rev[4*MAXN];int findans, lans, rans, midans, rl;int sz;inline void pushdownk(int Ind){ swap(suml[Ind][0], suml[Ind][1]); swap(sumr[Ind][0], sumr[Ind][1]); swap(summid[Ind][0], summid[Ind][1]); swap(ans[Ind][0], ans[Ind][1]);}inline void pushdown(int Ind){ lazy[Ind<<1] ^= 1; lazy[Ind<<1|1] ^= 1; rev[Ind<<1] ^= 1; rev[Ind<<1|1] ^= 1; if(rev[Ind<<1]){ pushdownk(Ind<<1); rev[Ind<<1] ^= 1; } if(rev[Ind<<1|1]){ pushdownk(Ind<<1|1); rev[Ind<<1|1] ^= 1; } lazy[Ind] = 0;}inline void pushupk(int l, int r, int Ind, int k){ int mid = (l + r) >> 1; if(mid - l + 1 == summid[Ind<<1][k]) suml[Ind][k] = summid[Ind<<1][k] + suml[Ind<<1|1][k]; else suml[Ind][k] = suml[Ind<<1][k]; if(r - (mid+1) + 1 == summid[Ind<<1|1][k]) sumr[Ind][k] = sumr[Ind<<1][k] + summid[Ind<<1|1][k]; else sumr[Ind][k] = sumr[Ind<<1|1][k]; summid[Ind][k] = max(max(summid[Ind<<1][k], summid[Ind<<1|1][k]), sumr[Ind<<1][k] + suml[Ind<<1|1][k]); ans[Ind][k] = max(max(ans[Ind<<1][k], ans[Ind<<1|1][k]), max(suml[Ind][k], sumr[Ind][k])); ans[Ind][k] = max(ans[Ind][k], summid[Ind][k]);}inline void pushup(int l, int r, int Ind){ pushupk(l, r, Ind, 0); pushupk(l, r, Ind, 1);}inline void _Modify(int a, int b, int l, int r, int Ind, int d){ if(a <= l && r <= b){ lazy[Ind] ^= d; rev[Ind] ^= d; if(rev[Ind]){ pushdownk(Ind); rev[Ind] ^= 1; } return; } int mid = (l + r) >> 1; if(lazy[Ind]) pushdown(Ind); if(a <= mid){ _Modify(a, b, l, mid, Ind<<1, d); } if(b > mid){ _Modify(a, b, mid + 1, r,Ind<<1|1, d); } pushup(l, r, Ind);}inline void _Query(int a, int b, int l, int r, int Ind){ if(a <= l && r <= b){ if(findans == INF){ findans = ans[Ind][1]; lans = suml[Ind][1]; rans = sumr[Ind][1]; midans = summid[Ind][1]; rl = r - l + 1; return; } if(rl == midans) lans = midans + suml[Ind][1]; midans = max(max(midans, summid[Ind][1]), rans + suml[Ind][1]); if(r - l + 1 == summid[Ind][1]) rans = rans + summid[Ind][1]; else rans = sumr[Ind][1]; findans = max(max(findans, ans[Ind][1]), max(rans, rans)); findans = max(findans, midans); rl += r - l + 1; return; } int mid = (l + r) >> 1; if(lazy[Ind]) pushdown(Ind); if(a <= mid) { _Query(a, b, l, mid, Ind<<1); } if(b > mid) { _Query(a, b, mid + 1, r, Ind<<1|1);} pushup(l, r, Ind);}inline void _Build(int l, int r, int Ind){ if(l == r){ lazy[Ind] = 0; rev[Ind] = 0; suml[Ind][0] = sumr[Ind][0] = summid[Ind][0] = ans[Ind][0] = 1; return; } int mid = (l + r) >> 1; _Build(l, mid, Ind<<1); _Build(mid + 1, r,Ind<<1|1); pushup(l, r, Ind);}inline void Modify(int a, int b, int d){return _Modify(a, b, 1, sz, 1, d);}inline void Query(int a, int b) {return _Query(a, b, 1, sz, 1);}inline void Build(){return _Build(1, sz, 1);}int main(){ #ifdef LOCAL freopen("b.txt", "r", stdin); //freopen("b.out", "w", stdout); int T = 1; while(T--){ #endif // LOCAL //ios::sync_with_stdio(false); cin.tie(0); int n, m, i, x, t, l, r; scanf("%d", &n); sz = n; Build(); for(i = 1; i <= n; i++){ scanf("%d", &x); Modify(i, i, x); } scanf("%d", &m); while(m--){ scanf("%d%d%d", &t, &l, &r); if(t == 0){ findans = lans = rans = midans = INF; Query(l, r); printf("%d\n", findans); } else{ Modify(l, r, 1); } } #ifdef LOCAL cout << endl; } #endif // LOCAL return 0;}
Thank you!
------from ProLights
- UESTC 1592 An easy problem B 线段树区间合并
- 线段树:CDOJ1592-An easy problem B (线段树的区间合并)
- UESTC 87 Easy Problem With Numbers 线段树区间更新 逆元 分解质因数
- UESTC 1712 Easy Problem With Numbers (线段树区间修改+非互素逆元)
- UESTC 1597 An easy problem C 线段树+延迟操作+一次函数
- uestc 1425 线段树 区间合并
- UESTC 1546 线段树 区间合并
- 线段树:CDOJ1597-An easy problem C(区间更新的线段树)
- B - An easy problem
- B - An easy problem
- B - An easy problem
- hdoj 5475 An easy problem 【线段树单点更新 + 区间乘积】
- hdu5475 An easy problem(线段树+单点更新+区间求积)
- HDOJ5475 An easy problem(暴力 & 线段树)
- hdu 5475 An easy problem(线段树)
- hdu 5475 An easy problem 线段树
- hdu5475 An easy problem 线段树
- hdu 5475 An easy problem (线段树)
- audioTrack调用的简单流程图
- 用Phaser来制作一个html5游戏——flappy bird (二)
- Codeforces 803F Coprime Subsequences DP+GCD
- Spring异步发送http请求
- 关于linux扩容问题解决方法
- UESTC 1592 An easy problem B 线段树区间合并
- 逆波兰式的实现(Java)
- PHP设计模式——概述
- base64编码+号解码错误
- Spring中BeanPostProcessor
- javaMail学习(与spring集成)
- 加壳问题
- 取模(mod)与取余(rem)的区别
- 高级I/O函数总结