zoukankan      html  css  js  c++  java
  • P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II

    题目

    P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II

    静态多次询问区间逆序对。

    分析

    二次离线莫队模板。

    莫队是显然的,然后考虑怎么维护端点的移动,直接维护该怎么做:求当前区间多少个数比 (x) 大,多少个数比 (x) 小,可以离散化后直接值域树状数组。

    这样做的复杂度 (O(nsqrt{n}logn))

    考虑优化。

    我们可以把每次的询问改成前缀和的形式:

    ([1,r]) 中多少个数比 (r) 大,减掉 ([1,l-1]) 中多少个数比 (r) 大。

    那么区间移动的话前者显然是个类似前缀和的东西,直接预处理,树状数组维护。

    后者是一个定区间,我们可以考虑离线下来,把这个询问挂到 (l-1) 处,然后可以考虑值域分块,每次修改 (O(sqrt{n})),给比自己大的数块内直接(+1),大块直接整块标记(+1)

    这样做单次询问 (O(1)),直接调用当前块标记和当前位置的值之和即可。

    (Trick:)值域分块可以实现(O(sqrt{n}))单次修改,(O(1))询问这个数的排名

    代码

    #include <bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define ll long long
    const int N=1e5+5,INF=1e9+7;
    int n,m,idx,block,siz;
    int a[N],b[N],num1[N],num2[N];
    ll Ans[N],sum1[N],sum2[N];
    struct Que{int l,r,id;}Q[N];
    struct Query{
    	int l,r,tp,id;
    	Query(int tp=0,int l=0,int r=0,int id=0):tp(tp),l(l),r(r),id(id){}
    };
    inline bool Cmp(const Que &x,const Que &y){return ((x.l/block)^(y.l/block))?x.l<y.l:x.r<y.r;}
    int c[N];
    inline void Add(int x,int v){
    	for(;x<=n;x+=(x&(-x))) c[x]+=v;
    	return ;
    }
    inline int Ask(int x){
    	int res=0;
    	for(;x;x-=(x&(-x))) res+=c[x];
    	return res;
    }
    int bl[N],Pre[N],pre[N],L[N],R[N];
    inline void Modify1(int x){
    	if(Pre[bl[x]]) for(int i=L[bl[x]];i<=R[bl[x]];i++) pre[i]+=Pre[bl[x]];
    	Pre[bl[x]]=0;
    	for(int i=L[bl[x]];i<=x;i++) pre[i]++;
    	for(int i=1;i<=bl[x]-1;i++) Pre[i]++;
    	return ;
    }
    inline void Modify2(int x){
    	if(Pre[bl[x]]) for(int i=L[bl[x]];i<=R[bl[x]];i++) pre[i]+=Pre[bl[x]];
    	Pre[bl[x]]=0;
    	for(int i=x;i<=R[bl[x]];i++) pre[i]++;
    	for(int i=bl[x]+1;i<=siz;i++) Pre[i]++;
    	return ;
    }
    vector<Query>vec1[N],vec2[N];
    void Solve(){
    	int cnt=sqrt(idx);siz=1;L[siz]=1;
    	if(cnt*cnt<idx) cnt++;
    	for(int i=1;i<=idx;i++){
    		bl[i]=siz;
    		if(i%cnt==0) R[siz]=i,L[++siz]=i+1;
    	}
    	R[siz]=idx;
    	for(int i=1;i<=n;i++){
    		const int len=vec1[i].size();
    		for(int j=0;j<len;j++){
    			const int id=vec1[i][j].id,tp=vec1[i][j].tp,l=vec1[i][j].l,r=vec1[i][j].r;
    			for(int k=l;k<=r;k++) Ans[id]+=1ll*tp*(Pre[bl[a[k]+1]]+pre[a[k]+1]);
    		}
    		Modify1(a[i]);
    	}
    	memset(Pre,0,sizeof(Pre)),memset(pre,0,sizeof(pre));
    	for(int i=n;i>=1;i--){
    		const int len=vec2[i].size();
    		for(int j=0;j<len;j++){
    			const int id=vec2[i][j].id,tp=vec2[i][j].tp,l=vec2[i][j].l,r=vec2[i][j].r;
    			for(int k=l;k<=r;k++) Ans[id]+=1ll*tp*(Pre[bl[a[k]-1]]+pre[a[k]-1]); 
    		}
    		Modify2(a[i]);
    	}
    	return ;
    }
    signed main(){
    	read(n),read(m);block=355;
    	for(int i=1;i<=n;i++) read(a[i]),b[i]=a[i];
    	sort(b+1,b+n+1);
    	idx=unique(b+1,b+n+1)-b-1;
    	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+idx+1,a[i])-b;
    	for(int i=1;i<=m;i++) read(Q[i].l),read(Q[i].r),Q[i].id=i;
    	for(int i=1;i<=n;i++) num1[i]+=i-1-Ask(a[i]),Add(a[i],1),sum1[i]=sum1[i-1]+num1[i];
    	memset(c,0,sizeof(c));
    	for(int i=n;i>=1;i--) num2[i]+=Ask(a[i]-1),Add(a[i],1),sum2[i]=sum2[i+1]+num2[i];
    	sort(Q+1,Q+m+1,Cmp);
    	int l=1,r=0;
    	for(int i=1;i<=m;i++){
    		if(r<Q[i].r) Ans[Q[i].id]+=sum1[Q[i].r]-sum1[r],vec1[l].push_back(Query(-1,r+1,Q[i].r,Q[i].id));
    		if(r>Q[i].r) Ans[Q[i].id]-=sum1[r]-sum1[Q[i].r],vec1[l].push_back(Query(1,Q[i].r+1,r,Q[i].id));
    		r=Q[i].r;
    		if(l<Q[i].l) Ans[Q[i].id]-=sum2[l]-sum2[Q[i].l],vec2[r].push_back(Query(1,l,Q[i].l-1,Q[i].id));
    		if(l>Q[i].l) Ans[Q[i].id]+=sum2[Q[i].l]-sum2[l],vec2[r].push_back(Query(-1,Q[i].l,l-1,Q[i].id));
    		l=Q[i].l;
    	}
    	Solve();
    	for(int i=1;i<=m;i++) Ans[Q[i].id]+=Ans[Q[i-1].id];
    	for(int i=1;i<=m;i++) write(Ans[i]),putchar('
    ');
    	return 0;
    }
    
  • 相关阅读:
    面向对象与组合
    异常处理和三级菜单练习
    装饰器和生成器
    序列化模块
    leetcode_498. 对角线遍历
    leetcode_566. 重塑矩阵
    leetcode_59. 螺旋矩阵 II
    leetcode_54. 螺旋矩阵
    leetcode_396. 旋转函数
    leetcode_200. 岛屿数量
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14719573.html
Copyright © 2011-2022 走看看