• P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II 莫队二次离线


    题意:

    戳这里

    分析:

    • 暴力:

      区间询问,不强制在线,直接莫队,查询内容是区间逆序对,直接上树状数组,复杂度 (O(nsqrt nlog ))

    • 正解:

      时限:0.25s 空限:32M

      莫队二次离线板子题

      众所周知 莫队二次离线能快速解决区间逆序对问题

      我们考虑查询区间从 ([l_1,r_1]) 变为 ([l_1,r_2]) 时值的变化,首先我们规定 (cnt(l_1,r_1,l_2,r_2)) 表示区间 ([l_1,r_1,]) 和区间 ([l_2,r_2]) 的逆序对数

      我们先考虑从 ([l,r]) 移动到 ([l,r+1])(Delta ans=cnt(l,r,r+1,r+1)) 差分一下 (Delta ans=cnt(1,r,r+1,r+1)-cnt(1,l-1,r+1,r+1)) , 那么从 ([l_1,r_1]) 移动到 ([l_1,r_2])(displaystyle Delta ans=sum_{i=r_1+1}^{r_2} cnt(1,i-1,i,i)-cnt(1,l-1,r_1+1,r_2))

      对于这个式子的前半部分可以直接预处理出来,所以我们要做的就是处理后半部分,这是一个前缀和和区间逆序对的形式,由于莫队的复杂度我们可以知道,这些区间长度之和不会超过 (O(nsqrt n)) 所以我们可以把区间询问分到每一个对应的前缀上,然后每次用指针扫一下前缀,顺便处理一下每一个前缀处的询问,用一个数据结构查询一下

      我们发现指针扫描时只会插入 (O(n)) 个数但是有 (O(nsqrt n)) 的询问,所以我们需要一个 (O(sqrt n)) 插入但是能 (O(1)) 查询的数据结构 —— 值域分块

      我们按照莫队分 4 种情况讨论:

      1. (l<q[i].l)

        (displaystyle Delta ans=sum_{i=l}^{q[i].l}cnt(i,i,i+1,r)=sum_{i=l}^{q[i].l}cnt(i,i,1,r)-cnt(i,i,1,i)=cnt(l,q[i].l,1,r)-sum_{i=l}^{q[i].l}cnt(i,i,1,i))

      2. (l>q[i].l)

        同上,只不过范围变了一下

      3. (r<q[i].r)

        (displaystyle Delta ans=sum_{i=r+1}^{q[i].r}cnt(l,i-1,i,i)=sum_{i=r+1}^{q[i].r}cnt(1,i-1,i,i)-cnt(1,l-1,i,i)=-cnt(1,l-1,r+1,q[i].r)+sum_{i=r+1}^{q[i].r}cnt(1,i-1,i,i))

      4. (r>q[i].r)

        同上,范围变一下

      总复杂度 (O(nsqrt n+nlog ))

    代码:

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mk(x,y) make_pair(x,y)
    #define lc rt<<1
    #define rc rt<<1|1
    #define pb push_back
    #define fir first
    #define sec second
    #define inl inline
    #define reg register
    
    using namespace std;
    
    namespace zzc
    {
    	typedef long long ll;
    	inline int read()
    	{
    		int x=0,f=1;char ch=getchar();
    		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    		return x*f;
    	}
        
        const int maxn = 1e5+5;
        int n,m,blo,cnt,len,tot;
        int c[maxn],d[maxn],t[maxn],bel[maxn],lef[maxn],rig[maxn],w[maxn],tag[maxn];
        ll ans[maxn],num1[maxn],num2[maxn];
        struct que
        {
            int l,r,id;
        }q[maxn];
    
        bool cmp(que a,que b)
        {
            return (a.l/blo==b.l/blo)?a.r<b.r:a.l<b.l;
        }
    
        struct node
        {
            int opt,l,r,id;
            node(){};
            node(int opt,int l,int r,int id):opt(opt),l(l),r(r),id(id){}
        };
        vector<node> v1[maxn],v2[maxn];
    
        inl int lowbit(int x) {return x&(-x);}
        inl void modify(int x,int val=1) {for(int i=x;i<=n;i+=lowbit(i))t[i]+=val;}
        inl int query(int x) {int res=0;for(int i=x;i;i-=lowbit(i))res+=t[i];return res;}
        
        void update1(int x)
        {
            if(tag[bel[x]])for(int i=lef[bel[x]];i<=rig[bel[x]];i++) w[i]+=tag[bel[x]];tag[bel[x]]=0;
            for(int i=lef[bel[x]];i<=x;i++) w[i]++;
            for(int i=1;i<bel[x];i++) tag[i]++;
        }
    
        void update2(int x)
        {
            if(tag[bel[x]]) for(int i=lef[bel[x]];i<=rig[bel[x]];i++) w[i]+=tag[bel[x]];tag[bel[x]]=0;
            for(int i=x;i<=rig[bel[x]];i++) w[i]++;
            for(int i=bel[x]+1;i<=tot;i++) tag[i]++;
        }
    
        void solve()
        {
            int id,p,frm,to;
            lef[tot=1]=1;
            cnt=sqrt(len)+1;
            for(int i=1;i<=len;i++) {bel[i]=tot;if(i%cnt==0) rig[tot]=i,lef[++tot]=i+1;}rig[tot]=len;
            for(int i=1;i<=n;i++)
            {
                int siz=v1[i].size();
                for(int j=0;j<siz;j++)
                {
                    id=v1[i][j].id;p=v1[i][j].opt;frm=v1[i][j].l;to=v1[i][j].r;
                    for(int k=frm;k<=to;k++) ans[id]+=1ll*p*(tag[bel[c[k]+1]]+w[c[k]+1]);
                }
                update1(c[i]);
            }
            memset(tag,0,sizeof(tag));memset(w,0,sizeof(w));
            for(int i=n;i>=1;i--)
            {	
                int siz=v2[i].size();
                for(int j=0;j<siz;j++)
                {
                    id=v2[i][j].id;p=v2[i][j].opt;frm=v2[i][j].l;to=v2[i][j].r;
                    for(int k=frm;k<=to;k++) ans[id]+=1ll*p*(tag[bel[c[k]-1]]+w[c[k]-1]);
                }
                update2(c[i]);
            }
            
        }
    
    	void work()
    	{
    	    n=read();m=read();blo=355;
            for(int i=1;i<=n;i++) c[i]=d[i]=read();
        	sort(d+1,d+n+1);
            len=unique(d+1,d+n+1)-d-1;
            for(int i=1;i<=n;i++) c[i]=lower_bound(d+1,d+len+1,c[i])-d;
            for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
            for(int i=1;i<=n;i++) num1[i]=num1[i-1]+i-1-query(c[i]),modify(c[i]);
            memset(t,0,sizeof(t));
            for(int i=n;i>=1;i--) num2[i]=num2[i+1]+query(c[i]-1),modify(c[i]);
            sort(q+1,q+m+1,cmp);
            for(int i=1,l=1,r=0;i<=m;i++)
            {
                if(l>q[i].l) ans[q[i].id]+=(num2[q[i].l]-num2[l]),v2[r].pb(node(-1,q[i].l,l-1,q[i].id)),l=q[i].l;
                if(r<q[i].r) ans[q[i].id]+=(num1[q[i].r]-num1[r]),v1[l].pb(node(-1,r+1,q[i].r,q[i].id)),r=q[i].r;
                if(l<q[i].l) ans[q[i].id]+=(num2[q[i].l]-num2[l]),v2[r].pb(node(1,l,q[i].l-1,q[i].id)),l=q[i].l;
                if(r>q[i].r) ans[q[i].id]+=(num1[q[i].r]-num1[r]),v1[l].pb(node(1,q[i].r+1,r,q[i].id)),r=q[i].r;
            }
            solve();
            for(int i=1;i<=m;i++) ans[q[i].id] += ans[q[i - 1].id];
            for(int i=1;i<=m;i++) printf("%lld
    ",ans[i]);
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    [转]WebForm中使用MVC
    [转]外贸出口流程图
    [转]查看SQL Server被锁的表以及如何解锁
    [转]RDL Report in Visual Studio New page per Record
    [转]Sql Server Report Service 的部署问题
    [转]ASP.NET MVC4中@model使用多个类型实例的方法
    [转]告别写计划的烦恼!一页纸四步打造出一份牛逼的商业计划
    [转]LINQ: Using INNER JOIN, Group and SUM
    [转] 比特币『私钥』『公钥』『钱包地址』间的关系
    [转]SQL SERVER数据库删除LOG文件和清空日志的方案
  • 原文地址:https://www.cnblogs.com/youth518/p/14299384.html
Copyright © 2020-2023  润新知