51Nod1962 区间计数

这题与之前那道区间最值的题非常类似,依旧是二分区间,然后统计跨过中间点的区间贡献。

我们要选出小于等于和小于的,这样就可以算出相等的区间长了。

复杂度O(nlogn)

By:大奕哥

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 ll ans;int n;
 5 const int N=350005;
 6 void add(ll x){ans+=x;}
 7 int a[2][N],p[2][3],l[2][N],r[2][N];
 8 void solve(int ll,int rr)
 9 {
10     if(ll==rr){if(a[0][ll]==a[1][ll])add(1);return;}
11     int mid=ll+rr>>1;
12     solve(ll,mid);solve(mid+1,rr);
13     for(int k=0;k<=1;++k)
14     {
15         l[k][mid]=a[k][mid];for(int i=mid-1;i>=ll;--i)l[k][i]=max(l[k][i+1],a[k][i]);
16         r[k][mid]=a[k][mid];for(int i=mid+1;i<=rr;++i)r[k][i]=max(r[k][i-1],a[k][i]);
17     }
18     for(int k=0;k<=1;++k)for(int i=0;i<=3;++i)p[k][i]=mid;
19     for(int i=mid;i>=ll;--i)
20     {
21         for(int k=0;k<=1;++k)
22         {
23             while(p[k][0]<rr&&r[k][p[k][0]+1]<=l[k][i])p[k][0]++;
24             while(p[k][1]<rr&&r[k][p[k][1]+1]<l[k^1][i])p[k][1]++;
25             while(p[k][2]<rr&&r[k][p[k][2]+1]<=l[k^1][i])p[k][2]++;
26         }
27         if(l[0][i]==l[1][i])add(max(0,min(p[0][0],p[1][0])-mid));
28         else if(l[0][i]>l[1][i])add(max(0,min(p[1][2],p[0][0])-p[1][1]));
29         else add(max(0,min(p[0][2],p[1][0])-p[0][1]));
30     }
31     int pos=mid+1;
32     for(int i=mid+1;i<=rr;++i)
33     {
34         while(pos>ll&&max(l[1][pos-1],l[0][pos-1])<max(r[1][i],r[0][i]))--pos;
35         if(r[0][i]==r[1][i])add(max(0,mid-pos+1));
36     }
37 }
38 int main()
39 {
40     scanf("%d",&n);
41     for(int k=0;k<=1;++k)
42     for(int i=1;i<=n;++i)
43     scanf("%d",&a[k][i]);
44     solve(1,n);
45     printf("%lld\n",ans);
46     return 0;
47 }
时间: 2024-08-05 20:44:09

51Nod1962 区间计数的相关文章

51nod1962区间计数

考虑每个值作为最大值的区间实际上可以用单调栈求出来,即找到左边第一个比它大的数l[i],右边第一个比它大的r[i],那就是左端点在[l[i],i]右端点在[i,r[i]]的区间是以第i个数作为最大值. 这样的话可以看成二维平面上一个矩形区域,每个矩形区域有着一样的最大值,如果我们把最大值相同的矩形放在一起考虑,问题就变成了:最大值相同的a产生的矩形和b产生的矩形交的面积之和. 用一个扫描线去做,维护当前线上矩形交的长度now.具体是这样的:开2n个线段树,对于每一种最大值开线段树,分别用root

POJ 3286- How many 0&#39;s?(组合数学_区间计数)

How many 0's? Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3286 Appoint description:  System Crawler  (2015-04-18) Description A Benedict monk No.16 writes down the decimal representations of

51NOD 1962 区间计数 单调栈+二分 / 线段树+扫描线

 区间计数 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80 两个数列 {An} , {Bn} ,请求出Ans, Ans定义如下: Ans:=Σni=1Σnj=i[max{Ai,Ai+1,...,Aj}=max{Bi,Bi+1,...,Bj}] 注:[ ]内表达式为真,则为1,否则为0. 1≤N≤3.5×1051≤Ai,Bi≤N 样例解释: 7个区间分别为:(1,4),(1,5),(2,4),(2,5),(3,3),(3,5),(4,5) Input 第一行一个整数N 第二行

POJ 2155 Matrix (树状数组 &amp;&amp; 区间计数)

题意 : 给出一个N*N的矩阵, 矩阵只有可能包含0或1, 一开始则全部是0.对于矩阵可以进行两种操作, 第一种是输入 C x1 y1 x2 y2 表示, 对以(x1, y1)为左上角, 以(x2, y2)为右下角构成的矩形区域内的数全部进行取反操作, 即0变1.1变0.第二种是Q X Y, 表示查询现在这个矩阵的(X, Y)点到底是0还是1.总共有T次操作, 对于C操作进行相应的修改, 对于Q操作要对应输出! 分析 : 据说是楼教主出的题, 自己确实想不出什么高效的办法, 参考网上的题解, 才

POJ 2282-The Counting Problem(组合数学_区间计数)

The Counting Problem Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2282 Appoint description:  System Crawler  (2015-04-15) Description Given two integers a and b, we write the numbers between

51nod 1962 区间计数(单调栈+二分)

维护两个单调递减的栈,当i加进栈,位置x的数弹出的时候,在另一个栈中找到和这个数一样大的数,计算贡献(x-靠右左端点)*(i-x). #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn=500010,in

区间DP总结

做了一些区间DP的题目,总结如下 1.Multiplication Puzzle 原题地址:http://poj.org/problem?id=1651 题意: 给定一个序列,可以依次从序列中取走除了左右两端点之外的元素,每次取走一个元素,获得该元素乘以它左右两边元素乘积的点数,求可能的最小点数 题解: 枚举区间中最后一个被取走的元素,实现区间的分割,也就是状态的转移. 详细的解题报告 2.Dire Wolf 原题地址:http://acm.split.hdu.edu.cn/showproble

[Gym-101981J] Prime Game (组合计数)

题意:求for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) sum += f[i][j]; f[i][j]表示在序列从 i 位乘到第 j 位所形成的新的数的 不同质因子的个数. 思路:说是话,拿到题还是一开始想着能不能进行递推,比如先将每一个数进行 质因分解 然后用set不断更新统计个数来求和.但这样无论怎样都无法优化 (n^2) ,所以换思路再想. 就忽然想到了以前有一道做过的原题,题意是:给定一个长度为n的序列,然后求出每一个子区间不同数的个数和.而这一

topK

最大K个数: 当数据量小时:快排和堆排O(Nlog(N)):部分排序(选择or交换)O(N*K) 快排加分治O(N*log(K)):二分查找 当数据是整数且重复数比较多时:计数排序:若不是整数,则分区间计数. 当数据量大时: 1)小根堆:O(N*KlogK) 2)分治法:hash成M份数据,取每份数据的前K个.然后使用快排(分治)对M*K个数据求出K个数.[用MapReduce] 实际应用:当数据量大,且重复数据多时,求频率最高的K个 1)先用hash_map进行频率统计(得到一个数组) 2)然