# hdoj6701 Make Rounddog Happy（单调栈维护区间最大+分治）

### 数据范围：

$1<=n<=3e5,1<=a_i<=n$。

### 分析：

 1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const int maxn=3e5+10;
5 int a[maxn],L[maxn],L2[maxn],R[maxn],R2[maxn],q[maxn],num[maxn],len[maxn];
6 int main(){
7 //    freopen("in.txt","r",stdin);
8 //    freopen("out.txt","w",stdout);
9     int t,n,k;scanf("%d",&t);
10     while (t--){
11         scanf("%d%d",&n,&k);
12         for (int i=1;i<=n;i++) scanf("%d",&a[i]),len[i]=max(1,a[i]-k);
13         int top=0;
14         for (int i=1;i<=n;i++){
15             while (top && a[q[top]]<a[i]) top--;
16             if (top==0) L[i]=1; else L[i]=q[top]+1;
17             q[++top]=i;
18         }
19         top=0;
20         for (int i=n;i>=1;i--){
21             while (top && a[q[top]]<a[i]) top--;
22             if (top==0) R[i]=n; else R[i]=q[top]-1;
23             q[++top]=i;
24         }
25         for (int i=1;i<=n;i++) num[i]=0;top=0;
26         for (int i=1;i<=n;i++){
27             while (top<n && num[a[top+1]]==0){
28                 top++; num[a[top]]++;
29             }
30             L2[i]=top;
31             num[a[i]]--;
32         }
33         for (int i=1;i<=n;i++) num[i]=0;top=n+1;
34         for (int i=n;i>=1;i--){
35             while (top>1 && num[a[top-1]]==0){
36                 top--; num[a[top]]++;
37             }
38             R2[i]=top;
39             num[a[i]]--;
40         }
41         ll ans=0;
42         for (int i=1;i<=n;i++){
43             if (i-L[i]+1<=R[i]-i+1){
44                 for (int j=L[i];j<=i;j++){
45                     if (L2[j]<i) continue;
46                     int rr=min(L2[j],R[i]);//右界
47                     int nn=i-j+1; //a[i]左侧的长度
48                     if (len[i]<=nn) ans+=rr-i+1;
49                     else ans+=max(0,rr-a[i]+k-j+2);
50                 }
51             }
52             else{
53                 for (int j=i;j<=R[i];j++){
54                     if (R2[j]>i) continue;
55                     int ll=max(R2[j],L[i]);//左界
56                     int mm=j-i+1; //a[i]右侧的长度
57                     if (len[i]<=mm) ans+=i-ll+1;
58                     else ans+=max(0,j+1-a[i]+k-ll+1);
59                 }
60             }
61         }
62         printf("%lld\n",ans);
63     }
64     return 0;
65 }

posted @ 2019-08-22 02:59  Changer-qyz  阅读(117)  评论(0编辑  收藏