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;
    }
    
  • 相关阅读:
    Combine 框架,从0到1 —— 4.在 Combine 中使用计时器
    Combine 框架,从0到1 —— 4.在 Combine 中使用通知
    Combine 框架,从0到1 —— 3.使用 Subscriber 控制发布速度
    Combine 框架,从0到1 —— 2.通过 ConnectablePublisher 控制何时发布
    使用 Swift Package Manager 集成依赖库
    iOS 高效灵活地配置可复用视图组件的主题
    构建个人博客网站(基于Python Flask)
    Swift dynamic关键字
    Swift @objcMembers
    仅用递归函数操作逆序一个栈(Swift 4)
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14719573.html
Copyright © 2011-2022 走看看