标签:pre int Segments codeforces ST Permutation 区间 最大值 define
题目链接:https://codeforc.es/contest/1156/problem/E
题目大意:
在数组p中可以找到多少个不同的l,r满足。
思路:
ST表+并查集。
ST表还是需要的,因为nlongn的预处理就可以O(1)查询。枚举所有的区间也就O(n^2)。
因为是输入固定1-n,所以我可以设一个y数组表示数组p的值所对应的下标。
(习惯输入为x数组)
我们考虑一个区间[l,r]这个区间最大值为i。(这里用ST表可以找到)
[l,r]对答案的贡献为最大值i左边找一个值a,右边找一个值b,满足a+b==i。有多少个不同的a,b对。
我们可以枚举i左右两边长度小的区间。然后在大区间上找。(小区间就可以少枚举点不是吗?最坏左右区间长度一样总共也就nlongn次)。
然后的问题是怎样找快速查找。
我们用并查集。
把大区间的所有值加入在大区间的最大值上。
你一定疑惑这样做还是会超时的啊。
如果在我们得到这个区间对答案的贡献后,把i左右两区间的最大值加在i上就可以完美的解决这个问题了。
我们直接从区间[1,n]开始,向下遍历,稍微注意一下边缘条件就OK啦。
整个就像一个线段树呢。
人太垃圾,ST表直接复制的板子,如有抄袭希望可以交个朋友哈~~
#include<bits/stdc++.h> using namespace std; #define IOS ios::sync_with_stdio(false); #define int long long #define N 200100 #define mod 1000000007 int x[N]; int y[N]; int pre[N]; int find(int x) { int r=x; while(pre[r]!=r) r=pre[r]; int i=x,j; while(i!=r) { j=pre[i]; pre[i]=r; i=j; } return r; } void join(int x,int y) { int a=find(x); int b=find(y); if(a!=b) { pre[a]=b; } } void into() { for(int i=1; i<N; i++) { pre[i]=i; } } int st[N][22]; void init(int n) { n++; for (int i = 0; i < n; i++) st[i][0] = x[i]; for (int j = 1; (1 << j) <= n; j++) { for (int i = 0; i + (1 << j) - 1 < n; i++) st[i][j] = max(st[i][j - 1],st[i + (1 << (j - 1))][j - 1]); } } int search(int l, int r) { int k = (int)(log((double)(r - l + 1)) / log(2.0)); return max(st[l][k],st[r - (1 << k) + 1][k]); } int Ans; void dfs(int i,int l,int r) { int a=0,b=0; if(y[i]>l) { a=search(l,y[i]-1); //cout<<i<<" "<<a<<endl; dfs(a,l,y[i]-1); } if(y[i]<r) { b=search(y[i]+1,r); //cout<<i<<" "<<b<<endl; dfs(b,y[i]+1,r); } if(r-y[i]<y[i]-l) { for(int j=y[i]+1; j<=r; j++) { if(find(i-x[j])==a) { Ans++; } } } else { for(int j=l; j<=y[i]-1; j++) { if(find(i-x[j])==b) { Ans++; } } } if(a) join(a,i); if(b) join(b,i); } signed main() { IOS; into(); int n,a; cin>>n; for(int i=1; i<=n; i++) { cin>>x[i]; y[x[i]]=i; } init(n); dfs(n,1,n); cout<<Ans; return 0; }
标签:pre,int,Segments,codeforces,ST,Permutation,区间,最大值,define 来源: https://www.cnblogs.com/opooopooo/p/10806312.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。