• codeforces 997E(线段树)


    分析:

      首先考虑如何计算整个数组有多少个good区间

      容易发现一个区间是good区间当且仅当max-min-len=-1,且任意区间max-min-len>=-1

      我们可以枚举右端点,然后维护前面每个位置到当前右端点的max-min-len值,容易发现我们只需要维护区间最小值和最小值的个数就行了,于是用线段树即可

      于是我们可以得到以某个点为右端点的时候合法区间总数,那么我们把每次的结果加起来,就得到了整个数组有多少个good区间

      每次右端点移动怎么更新呢?显然我们只需要用一个max单调栈,一个min单调栈来帮助寻找修改区间,容易知道修改区间的个数是O(n)级别的,所以整个修改是O(nlogn)的

      好,现在我们回到原来的问题,如何求[l,r]内有多少个good区间

      在这个问题中,我们实际上要额外知道“每个区间的历史答案和”,这是什么意思呢,比如说在i=7的时候,[4,7]里的答案存的是有多少个合法的位置是和7匹配的

      但i=6的时候,[4,7]里的答案存的是有多少个合法的位置是和6匹配的

      我们自然而然就考虑到把每个右端点时刻,一个区间的产生的答案值加起来就行了,但这个时间复杂度是巨大的

      这里我们仍然可以用延迟标记来解决,比如右端点i枚举完了,我们可以给[1,i]上个tag,表示这整个区间的历史答案需要加上现在时刻的答案

      时间复杂度O(nlogn)

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define mp make_pair
      4 const int maxn=120000;
      5 struct wjmzbmr
      6 {
      7     int mi,num,tag;
      8     int time;
      9     long long ans;
     10 }tree[maxn*4+5];
     11 vector<pair<int,int> > q[maxn+5];
     12 long long ans[maxn+5];
     13 int a[maxn+5],s[maxn+5],s1[maxn+5];
     14 int len,len1;
     15 int n,m;
     16 void addtag(int k,int x)
     17 {
     18     tree[k].tag+=x;
     19     tree[k].mi+=x;
     20 }
     21 void addtime(int k,int x)
     22 {
     23     tree[k].time+=x;
     24     tree[k].ans+=1LL*x*tree[k].num;
     25 }
     26 void pushdown(int k)
     27 {
     28     if(tree[k].tag)
     29     {
     30         addtag(k*2,tree[k].tag);
     31         addtag(k*2+1,tree[k].tag);
     32         tree[k].tag=0;
     33     }
     34     if(tree[k].time)
     35     {
     36         if(tree[k].mi==tree[k*2].mi) addtime(k*2,tree[k].time);
     37         if(tree[k].mi==tree[k*2+1].mi) addtime(k*2+1,tree[k].time);
     38         tree[k].time=0;
     39     }
     40 }
     41 void update(int k)
     42 {
     43     tree[k].mi=min(tree[k*2].mi,tree[k*2+1].mi);
     44     tree[k].ans=tree[k*2].ans+tree[k*2+1].ans;
     45     tree[k].num=0;
     46     if(tree[k].mi==tree[k*2].mi) tree[k].num+=tree[k*2].num;
     47     if(tree[k].mi==tree[k*2+1].mi) tree[k].num+=tree[k*2+1].num;
     48 }
     49 void build(int k,int l,int r)
     50 {
     51     if(l>r) return;
     52     if(l==r)
     53     {
     54         tree[k].num=1;
     55         tree[k].mi=-1;
     56         return;
     57     }
     58     int mid=(l+r)>>1;
     59     build(k*2,l,mid);
     60     build(k*2+1,mid+1,r);
     61     update(k);
     62 }
     63 void modify(int k,int l,int r,int ql,int qr,int x)
     64 {
     65     if(r<ql||l>qr||l>r) return;
     66     if(l>=ql&&r<=qr)
     67     {
     68         addtag(k,x);
     69         return;
     70     }
     71     if(l==r) return;
     72     pushdown(k);
     73     int mid=(l+r)>>1;
     74     modify(k*2,l,mid,ql,qr,x);
     75     modify(k*2+1,mid+1,r,ql,qr,x);
     76     update(k);
     77 }
     78 void modify1(int k,int l,int r,int ql,int qr,int x)
     79 {
     80     if(r<ql||l>qr||l>r) return;
     81     if(l>=ql&&r<=qr)
     82     {
     83         if(tree[k].mi==-1)
     84         addtime(k,x);
     85         return;
     86     }
     87     if(l==r) return;
     88     pushdown(k);
     89     int mid=(l+r)>>1;
     90     modify1(k*2,l,mid,ql,qr,x);
     91     modify1(k*2+1,mid+1,r,ql,qr,x);
     92     update(k);
     93 }
     94 long long query(int k,int l,int r,int ql,int qr)
     95 {
     96     if(r<ql||l>qr||l>r) return 0;
     97     if(l>=ql&&r<=qr) return tree[k].ans;
     98     if(l==r) return 0;
     99     pushdown(k);
    100     int mid=(l+r)>>1;
    101     long long ans=query(k*2,l,mid,ql,qr)+query(k*2+1,mid+1,r,ql,qr);
    102     update(k);
    103     return ans;
    104 }
    105 int main()
    106 {
    107     scanf("%d",&n);
    108     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    109     scanf("%d",&m);
    110     for(int i=1;i<=m;++i)
    111     {
    112         int l,r;
    113         scanf("%d%d",&l,&r);
    114         q[r].push_back(mp(l,i));
    115     }
    116     build(1,1,n);
    117     for(int i=1;i<=n;++i)
    118     {
    119         while(len&&a[s[len]]<a[i]) modify(1,1,n,s[len-1]+1,s[len],a[i]-a[s[len]]),--len;
    120         s[++len]=i;
    121         //for(int j=1;j<=len;++j) printf("%d ",a[s[j]]);printf("
    ");
    122         while(len1&&a[s1[len1]]>a[i]) modify(1,1,n,s1[len1-1]+1,s1[len1],a[s1[len1]]-a[i]),--len1;
    123         s1[++len1]=i;
    124         //for(int j=1;j<=len1;++j) printf("%d ",a[s1[j]]);printf("
    ");
    125         modify1(1,1,n,1,i,1);
    126         for(auto x:q[i]) ans[x.second]=query(1,1,n,x.first,i);
    127         //printf("%lld
    ",query(1,1,n,1,i));
    128         //if(i==4) printf("%d
    ",tree[2].ans);
    129         modify(1,1,n,1,i,-1);
    130 
    131     }
    132     for(int i=1;i<=m;++i) printf("%lld
    ",ans[i]);
    133     return 0;
    134 }
    View Code
  • 相关阅读:
    VUE iframe消息通信postMessage
    sqlserver 增加新列并加备注说明备用
    实用的apipost 软件,登录token改变,其他请求也随之改变自带token请求设置
    介绍一下magic.net多租户的应用
    vue 给路由增加自定义信息meta属性
    hyperv 设置NAT网络备忘
    mybatis plus 多字段排序
    c#使用redis
    centos ssh连接卡在【To escape to local shell, press 'Ctrl+Alt+]'.】的解决方法
    java stream 转字符串数组
  • 原文地址:https://www.cnblogs.com/wmrv587/p/9261128.html
Copyright © 2020-2023  润新知