CF 452F Permution 神奇的线段树判断
2016-08-18 14:50
411 查看
题目大意
给定一个1到N的列,问是否存在一个长度为3的子等差数列。N≤300000
解题思路
看到这题,感觉有点无从下手,好像怎么要都要枚举两个值。但是我们可以发现一个很神奇的性质如果对于一个位置i,它是子等差序列中的第二项,那么如果不存在长度为3的子等差数列,那么Ai+k和Ai−k在位置i前肯定是成对存在的,即如果我们把位置i前出现的数都在数组上打上tag,那么这些tag肯定是关于Ai对称的(在边界之内)!那么我们可以用Hash来维护数组中连续一段数的存在情况,但是对于数组中任意一个位置都要判断是否合法。那么只需在线段树上打tag,然后线段树中每个结点存的是Hash值,那么从前往后,边维护边判断即可。
程序
//YxuanwKeith #include <cstring> #include <cstdio> #include <algorithm> using namespace std; typedef long long LL; const int Mo = 1e9 + 7; const int MAXN = 3e5 + 5; struct Node { LL Num; int len; Node (LL num, int Len) {Num = num, len = Len;} Node (){} } Tr[2][MAXN * 4]; int N; LL Pow[MAXN]; Node Merge(Node L, Node R) { Node New; New.len = L.len + R.len; New.Num = (1ll * L.Num * Pow[R.len] + R.Num) % Mo; return New; } void Build(int Ord, int Now, int l, int r) { Tr[Ord][Now].len = r - l + 1; if (l == r) return; int Mid = (l + r) >> 1; Build(Ord, Now * 2, l, Mid), Build(Ord, Now * 2 + 1, Mid + 1, r); } void Modify(int Ord, int Now, int l, int r, int Side) { if (l == r) { Tr[Ord][Now].Num = 1; return; } int Mid = (l + r) >> 1; if (Side <= Mid) Modify(Ord, Now * 2, l, Mid, Side); else Modify(Ord, Now * 2 + 1, Mid + 1, r, Side); if (!Ord) Tr[Ord][Now] = Merge(Tr[Ord][Now * 2], Tr[Ord][Now * 2 + 1]); else Tr[Ord][Now] = Merge(Tr[Ord][Now * 2 + 1], Tr[Ord][Now * 2]); } Node Query(int Ord, int Now, int l, int r, int lx, int rx) { if (lx > rx) return Node(0, 0); if (l == lx && r == rx) return Tr[Ord][Now]; int Mid = (l + r) >> 1; if (rx <= Mid) return Query(Ord, Now * 2, l, Mid, lx, rx); else if (lx > Mid) return Query(Ord, Now * 2 + 1, Mid + 1, r, lx, rx); else { Node L = Query(Ord, Now * 2, l, Mid, lx, Mid); Node R = Query(Ord, Now * 2 + 1, Mid + 1, r, Mid + 1, rx); if (!Ord) return Merge(L, R); else return Merge(R, L); } } int main() { freopen("data.in", "r", stdin), freopen("data.out", "w", stdout); scanf("%d", &N); Pow[0] = 1; Build(0, 1, 1, N), Build(1, 1, 1, N); for (int i = 1; i <= N; i ++) Pow[i] = 1ll * Pow[i - 1] * 2 % Mo; for (int i = 1; i <= N; i ++) { int Now; scanf("%d", &Now); int len = min(Now - 1, N - Now); if (Query(0, 1, 1, N, Now - len, Now - 1).Num != Query(1, 1, 1, N, Now + 1, Now + len).Num) { printf("YES\n"); return 0; } Modify(0, 1, 1, N, Now); Modify(1, 1, 1, N, Now); } printf("NO\n"); }
相关文章推荐
- CF 339D - Xenia and Bit Operations(线段树)
- CF 179(div2) C(线段树 || 扫描法 )
- Codeforces Round #271 (Div. 2)(dp,线段树good)(很好的一场cf)
- JZOJ4774 【GDOI2017模拟9.10】子串 线段树合并维护SAM的fail树信息(CF 666E类似)
- CF 454B(Little Pony and Sort by Shift-序列位移后单调性判断及最小位移[水])
- CF 18A(近似直角三角形判断+向量直角公式+switch+istream&(..&P a))
- 【CF875E】Delivery Club 二分+线段树
- Cf 444C DZY Loves Colors(线段树)
- 线段树优化连边(cf 786B)
- bzoj 3790: 神奇项链 (manacher+线段树优化DP)
- CF 线段树 gcd改变
- CF 283E Cow Tennis Tournament(线段树)
- CF-85D-Sum of Medians(线段树)
- cf 768 B(二分搜索+线段树思维)@
- [CF 61E]Enermy is weak[线段树求二重逆序数]
- CF 558E 线段树
- poj 3067 Japan(线段树?,神奇卡时代码,暂未完)
- CF 6E 线段树 or Multiset or 双端队列维护区间最值
- CF Codeforces 52C 简单的线段树 成段更新
- 哈理工OJ 1997 又是一个神奇的布尔矩阵(判断)