CodeForces 193D. Two Segments线段树

Posted bakacirno

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces 193D. Two Segments线段树相关的知识,希望对你有一定的参考价值。

传送门
补这道题的契机是因为烂桥杯2013的最后一题,虽然那道题暴力也能过,但看到大佬介绍的线段树做法,感觉又刷新了我对于线段树的认识,果然线段树是无所不能的

题意

给你一个 (n) 的全排列 (A),你可以从中选两个不重合的区间,如果这两个区间里的所有数按升序排列是一个公差为 (1) 的等差数列,则是一种合法方案,若两组不同区间包含的数相同,则视为一种方案。问一共有多少种合法方案。

题解

考虑如果已知正整数区间 ([l,r]) 在原全排列 (A) 中被分为 (k) 段,此时加入 (r+1),有如下情况:

  • 如果 (r+1)([l,r]) 中任意一个数都不相邻,那么 ([l,r+1]) 被分为 (k+1) 段。
  • 如果 (r+1)([l,r]) 中一个数相邻,那么 ([l,r+1]) 依然被分为 (k) 段。
  • 如果 (r+1)([l,r]) 中两个数相邻,那么 ([l,r+1]) 被分为 (k-1) 段。

既然这样可以得到一个 (O(n^2)) 的算法,这里就不赘述了。因为这道题的数据范围是 (nle 300,000)(O(n^2)) 的算法是接受不了的。
但是根据上述的分段变化规律,我们发现可以对区间进行更改,也就是说,以 (f[l,r]) 表示 ([l,r]) 被拆分的段数,如果已知 (f[1,r],f[2,r],...,f[r,r]),这时对这些区间都加入 (r+1),有以下情况:

  • 如果在 ([1,r]) 中没有数与 (r+1)(A) 中相邻,那么:
    [ f[i,r+1]=f[i,r]+1 ]

  • 如果在 ([1,r]) 有只一个数 (x)(r+1)(A) 中相邻,([i,r+1](1le ile x)) 被分的段数会和 ([i,r]) 一样,因为 (r+1) 是和 (x) 紧紧贴♂在一起的嘛;而 ([i,r+1](x+1le ile r+1))([i,r]) 所分的段数多 (1),原因就是 ([i,r]) 中没有数和 (r+1) 相邻,那么 (r+1) 会单独构成一段。所以这种情况可以表示为:
    [ egin{aligned} f[i,r+1] & = f[i,r] &, &&1le &ile x f[i,r+1] & = f[i,r]+1 &, &&x+1le &ile r+1 end{aligned} ]

  • 如果在 ([l,r]) 中有两个数 (x,y(x<y))(r+1)(A) 中相邻,那么 ([i,r+1](1le ile x)) 被分的段数比 ([i,r])(1),因为本来 (x,y) 是裂开的,加入 (r+1) 后这两段合起来了;而 ([i,r+1](x+1le ile y))([i,r]) 相等,因为只有 (y) 一个数和 (r+1) 贴;而 ([i,r+1](y+1le ile r+1))([i,r])(1)。可表示为:
    [ egin{aligned} f[i,r+1] &= f[i,r]-1 &, &&1le &ile x f[i,r+1] &= f[i,r] &, &&x+1le &ile y f[i,r+1] &= f[i,r]+1 &, &&y+1le &ile r+1 end{aligned} ]

所以我们就可以用线段树来维护决定 (r)(f[i,r]) 的值,根据题意,每次加入 (r+1) 之后,只需要查询线段树中值为 (1)(2) 的叶节点的个数就行了。

简单说一下线段树的写法

因为根据 (f[l,r]) 的性质就可以知道线段树叶节点的最小值就是 (1),那么要查 (1)(2) 的个数,只需要维护区间最小值和最小值的个数和最小值 (+1) 的个数就行了。
注意 pushup 操作的写法,统计区间最小值,然后通过最小值查询左右子树中最小值的个数,尤其不要忘了统计全最小值 (+1) 的个数。

代码

#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N=3e5+10;
int n,a[N],p[N];

struct SegTree{
    #define mid (l+r>>1)
    int num1[N*4],num2[N*4],minv[N*4],tag[N*4];
    void pushdown(int id){
        minv[id<<1]+=tag[id];tag[id<<1]+=tag[id];
        minv[id<<1|1]+=tag[id];tag[id<<1|1]+=tag[id];
        tag[id]=0;
    }
    void pushup(int id){
        minv[id]=min(minv[id<<1],minv[id<<1|1]);
        num1[id]=num2[id]=0;
        if(minv[id<<1]==minv[id]) num1[id]+=num1[id<<1],num2[id]+=num2[id<<1];
        else if(minv[id<<1]==minv[id]+1) num2[id]+=num1[id<<1];
        if(minv[id<<1|1]==minv[id]) num1[id]+=num1[id<<1|1],num2[id]+=num2[id<<1|1];
        else if(minv[id<<1|1]==minv[id]+1) num2[id]+=num1[id<<1|1];
    }
    void build(int id,int l,int r){
        num1[id]=r-l+1;
        if(l==r) return;
        build(id<<1,l,mid);
        build(id<<1|1,mid+1,r);
    }
    void upd(int id,int l,int r,int L,int R,int x){
        if(L<=l&&r<=R) {minv[id]+=x;tag[id]+=x;return;}
        if(tag[id]) pushdown(id);
        if(L<=mid) upd(id<<1,l,mid,L,R,x);
        if(R>mid) upd(id<<1|1,mid+1,r,L,R,x);
        pushup(id);
    }
    int ask(int id,int l,int r,int L,int R){
        if(L<=l&&r<=R) {
            if(minv[id]==1) return num1[id]+num2[id];
            if(minv[id]==2) return num1[id];
            return 0;
        }
        if(tag[id]) pushdown(id);
        int res=0;
        if(L<=mid) res+=ask(id<<1,l,mid,L,R);
        if(R>mid) res+=ask(id<<1|1,mid+1,r,L,R);
        return res;
    }
    #undef mid
}tr;

int main(){
    scanf("%d",&n);
    for(int i=1,x;i<=n;i++) scanf("%d",&x),p[x]=i;
    LL ans=0;
    tr.build(1,1,n);
    for(int i=1;i<=n;i++){
        a[p[i]]=i;
        int x=a[p[i]-1],y=a[p[i]+1];
        if(x>y) swap(x,y);
        if(x) tr.upd(1,1,n,1,x,-1),tr.upd(1,1,n,y+1,i,1);
        else if(y) tr.upd(1,1,n,y+1,i,1);
        else tr.upd(1,1,n,1,i,1);
        ans+=tr.ask(1,1,n,1,i);
        //cout<<"->"<<ans<<endl;
    }
    ans-=n;
    cout<<ans<<endl;
    return 0;
}

以上是关于CodeForces 193D. Two Segments线段树的主要内容,如果未能解决你的问题,请参考以下文章

CodeForces - 240D. Merging Two Decks 贪心+暴力

Codeforces1138-A(D题)Sushi for Two

codeforces 1560D. Make a Power of Two 模拟+暴力

Two progressions(CodeForces-125D)[鸽巢原理]

题解CF193D Two Segments

codeforces193B