ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[TJOI2017]不勤劳的图书管理员(分块+树状数组)

2019-05-23 12:49:57  阅读:228  来源: 互联网

标签:树状 int ll 分块 long TJOI2017 数组


有一个数组开大会MLE开小会RE的做法:就是树套树,即树状数组套主席树,这种方法比较暴力,然而很遗憾它不能通过,因为其时空复杂度均为O(nlog2n)。

想到一种不怎么耗内存,以时间换空间,分块!单次修改(l,r)只对点对(l,r)、(l,i)和(i,r)产生影响,其中l<i<r,然后可以考虑分块,每块维护每个p[i]出现的次数,交换时块内直接查询即可,而修改也可以直接修改,套上树状数组即可在O(logn)内的时间维护。设块大小为k,时间复杂度为O(nlogn+mk+mnlogn/k),当k取√(nlogn)时,复杂度最优,此时复杂度为O(nlogn+m√(nlogn))。空间复杂度也不会爆炸,为O(n√n)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+7,mod=1e9+7;
int n,m,B,p[N];
ll ans,s[2][250][N],v[N];
void add(int t,int id,int x,ll v)
{
    if(!x)return;
    while(x<=n)s[t][id][x]=(s[t][id][x]+v+mod)%mod,x+=x&-x;
}
ll ask(int t,int id,int x)
{
    if(x<0)return 0;
    ll ret=0;while(x)ret=(ret+s[t][id][x])%mod,x-=x&-x;
    return ret;
}
void calc(int a,int b,int c)
{
    if(p[a]<p[c])ans=(ans+v[a]+v[c])%mod;else ans=(ans-v[a]-v[c]+2*mod)%mod;
    if(p[b]<p[c])ans=(ans-v[b]-v[c]+2*mod)%mod;else ans=(ans+v[b]+v[c])%mod;
}
int main()
{
    scanf("%d%d",&n,&m),B=sqrt(n*17);
    for(int i=0;i<n;i++)scanf("%d%lld",&p[i],&v[i]),add(0,i/B,p[i],v[i]),add(1,i/B,p[i],1);
    for(int i=n-1;~i;i--)
    {
        ans=(ans+ask(0,n/B+1,p[i])+ask(1,n/B+1,p[i])*v[i])%mod;
        add(0,n/B+1,p[i],v[i]),add(1,n/B+1,p[i],1);
    }
    while(m--)
    {
        int x,y,idx,idy;scanf("%d%d",&x,&y),x--,y--;
        if(x==y){printf("%lld\n",ans);continue;}
        if(x>y)swap(x,y);
        idx=x/B,idy=y/B;
        if(p[x]<p[y])ans=(ans+v[x]+v[y])%mod;else ans=(ans-v[x]-v[y]+2*mod)%mod;
        if(idx==idy)
        {
            for(int j=x+1;j<y;j++)calc(x,y,j);
            swap(p[x],p[y]),swap(v[x],v[y]);
            printf("%lld\n",ans);
            continue;
        }
        for(int j=x+1;j<idx*B+B;j++)calc(x,y,j);
        for(int j=idy*B;j<y;j++)calc(x,y,j);
        for(int j=idx+1;j<idy;j++)
        {
            ans=(ans-2*ask(0,j,p[x])+ask(0,j,n)-(2*ask(1,j,p[x])-B+mod)*v[x]%mod+mod)%mod;
            ans=(ans+2*ask(0,j,p[y])-ask(0,j,n)+(2*ask(1,j,p[y])-B+mod)*v[y]%mod+mod)%mod;
        }
        add(0,idx,p[x],-v[x]),add(0,idy,p[y],-v[y]),add(1,idx,p[x],-1),add(1,idy,p[y],-1);
        swap(p[x],p[y]),swap(v[x],v[y]);
        add(0,idx,p[x],v[x]),add(0,idy,p[y],v[y]),add(1,idx,p[x],1),add(1,idy,p[y],1);
        printf("%lld\n",ans);
    }
}
View Code

 

标签:树状,int,ll,分块,long,TJOI2017,数组
来源: https://www.cnblogs.com/hfctf0210/p/10911209.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有