题意:

有一个长度为n的序列a和一个相同长度的序列b,a初始都为0,b初始为乱序的全排列。现在有两种操作,共操作q次:

add l r:对于加一;

query l r:询问

其中

思路:

在经过q次操作之后,最大为,因为b为全排列,有调和级数

建立两棵线段树,一棵树A维护序列a的最小值,另一棵树B维护的和。

对于add操作,将A的区间减1,时间复杂度为。当发现该区间的最小值等于0,就向下dfs,找到那个最小值为0的叶子,对这个叶子对应的进行修改,复杂度上面证明了应该为

所以总的复杂度为

比赛的时候就是卡在要如何知道哪个点要对进行修改,也没想到这个全排列居然是这么用的,有勇气的时候还是要暴力一发啊…不要怕写之后要调很久(虽然补题的时候的确调了很久…懒标记下放的地方没有累加啊…

写线段树的时候也仔细一点吧。

代码:

typedef long long ll;
ll tot;
ll ori[100010];
int num;
struct node1
{
    int l,r;
    ll mmin,f1;
    ll sum;
    int pos;
}b[100010<<2];
void build(int L,int R,int id)
{
    b[id].l=L;b[id].r=R;
    b[id].f1=0;
    b[id].sum=0;
    if(L==R)
    {
        b[id].mmin=ori[++num];
        b[id].pos=num;
        return;
    }
    int m=(L+R)>>1;
    build(L,m,id<<1);
    build(m+1,R,id<<1|1);
    b[id].mmin=min(b[id<<1].mmin,b[id<<1|1].mmin);
}
void pushdown1(int id)
{
    ll c=b[id].f1;
    b[id<<1].mmin-=c;b[id<<1|1].mmin-=c;
    b[id<<1].f1+=b[id].f1;b[id<<1|1].f1+=b[id].f1;
    b[id].f1=0;
}
void update2(int loc,int id)
{
    int l=b[id].l,r=b[id].r;
    if(l==r)
    {
        b[id].sum++;
        return;
    }
    int m=(l+r)>>1;
    if(loc<=m)update2(loc,id<<1);
    if(loc>m)update2(loc,id<<1|1);
    b[id].sum=b[id<<1].sum+b[id<<1|1].sum;
}
void update(int loc,ll c,int id)
{
    int l=b[id].l,r=b[id].r;
    if(l==r)
    {
        b[id].mmin=c;
        return;
    }
    int m=(l+r)>>1;
    if(loc<=m)update(loc,c,id<<1);
    if(loc>m)update(loc,c,id<<1|1);
    b[id].mmin=min(b[id<<1].mmin,b[id<<1|1].mmin);
}
void dfs(int id)
{
    int l=b[id].l,r=b[id].r;
    if(l==r)
    {
        if(b[id].mmin==0)
        {
            update(b[id].pos,ori[b[id].pos],1);
            update2(b[id].pos,1);
        }
        return;
    }
    if(b[id].f1!=0)pushdown1(id);
    if(b[id<<1].mmin==0)dfs(id<<1);
    if(b[id<<1|1].mmin==0)dfs(id<<1|1);
    b[id].mmin=min(b[id<<1].mmin,b[id<<1|1].mmin);
}
void update1(int L,int R,int id)
{
    int l=b[id].l,r=b[id].r;
    if(l>=L&&r<=R)
    {
        b[id].mmin--;
        b[id].f1++;
        if(b[id].mmin==0)
            dfs(id);
        return;
    }
    if(b[id].f1!=0)pushdown1(id);
    int m=(l+r)>>1;
    if(L<=m)update1(L,R,id<<1);
    if(R>m)update1(L,R,id<<1|1);
    b[id].mmin=min(b[id<<1].mmin,b[id<<1|1].mmin);
}
void query(int L,int R,int id)
{
    int l=b[id].l,r=b[id].r;
    if(l>=L&&r<=R)
    {
        tot+=b[id].sum;
        return;
    }
    int m=(l+r)>>1;
    if(L<=m)query(L,R,id<<1);
    if(R>m)query(L,R,id<<1|1);
}
int main()
{
    int n,q,x,y;
    char s[10];
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%lld",&ori[i]);
        num=0;
        build(1,n,1);
        while(q--)
        {
            scanf("%s",s);
            scanf("%d%d",&x,&y);
            if(s[0]=='a')
                update1(x,y,1);
            else if(s[0]=='q')
            {
                tot=0;
                query(x,y,1);
                printf("%lld\n",tot);
            }
        }
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

徐州邀请赛I 类矩阵快速幂 Previous
HDU6299 贪心 Next