• P5501 [LnOI2019]来者不拒,去者不追


    来者不拒,去者不追

    考虑莫队,挪动指针往区间 \([l,r]\) 中加入一个数 \(x\),产生的贡献就是 \(比 x 大的数之和 + 比 x 小的数的个数\times x +x\)
    然后这样是 \(O(n\sqrt m \log n\)) 的

    发现如果不加最后那个 \(x\) 的话就是可差分的(等于对 \([1,r]\) 的贡献减去对 \([1,l]\) 的贡献),于是考虑二次离线
    预处理简单,二次离线的时候会产生 \(O(n)\) 此插入一个数的修改和 \(O(n\sqrt n)\) 此询问上面的那两个信息
    在值域上分块做到 \(O(1)\) 查询,\(O(\sqrt n)\) 修改即可

    最后输出前把那个 \(x\) 加回来

    #define N 500006
    #define B 707
    #define V 100000
    #define VB 316
    int n,m;
    struct Ask{
    	int l,r,id;
    };
    Ask ask[N];
    struct Node{
    	int L,R,i,k;
    };
    std::vector<Node>change[N];
    int belong[N];
    long long a[N];
    long long bsum[VB+6],sum[V+6],bnum[VB+6],num[V+6];
    long long fxx[N],ans[N];
    inline void pre(){
    	for(int i=1;i<=V;i++) belong[i]=(i-1)/VB+1;
    	for(int i=1;i<=n;i++){
    		fxx[i]=bsum[belong[a[i]]]+sum[a[i]]+a[i]*(bnum[belong[a[i]]]+num[a[i]]);
    		for(int j=a[i]-1;belong[j]==belong[a[i]];j--) sum[j]+=a[i];
    		for(int j=belong[a[i]]-1;j;j--) bsum[j]+=a[i];
    		for(int j=a[i]+1;belong[j]==belong[a[i]];j++) num[j]++;
    		for(int j=belong[a[i]]+1;j<=belong[V];j++) bnum[j]++;
    	}
    	for(int i=1;i<=n;i++) fxx[i]+=fxx[i-1];
    	std::memset(bsum,0,sizeof bsum);std::memset(sum,0,sizeof sum);std::memset(bnum,0,sizeof bnum);std::memset(num,0,sizeof num);
    }
    int main(){
    	n=read();m=read();
    	for(int i=1;i<=n;i++) a[i]=read(),belong[i]=(i-1)/B+1;
    	for(int i=1;i<=m;i++) ask[i].l=read(),ask[i].r=read(),ask[i].id=i;
    	std::sort(ask+1,ask+1+m,[](const Ask &a,const Ask &b){return belong[a.l]==belong[b.l]?a.r<b.r:a.l<b.l;});
    	pre();
    	for(int l=1,r=0,L,R,i=1;i<=m;i++){
    		L=ask[i].l;R=ask[i].r;
    		if(r<R) change[l-1].push_back({r+1,R,i,-1}),ans[ask[i].id]+=fxx[R]-fxx[r],r=R;
    //		while(r<ask[i].r) ans[ask[i].id]+=fxx[++r];
    		if(l>L) change[r].push_back({ask[i].l,l-1,i,1}),ans[ask[i].id]-=fxx[l-1]-fxx[L-1],l=L;
    //		while(l>ask[i].l) ans[ask[i].id]-=fxx[--l];
    		if(r>R) change[l-1].push_back({ask[i].r+1,r,i,1}),ans[ask[i].id]-=fxx[r]-fxx[R],r=R;
    //		while(r>ask[i].r) ans[ask[i].id]-=fxx[r--];
    		if(l<L) change[r].push_back({l,ask[i].l-1,i,-1}),ans[ask[i].id]+=fxx[L-1]-fxx[l-1],l=L;
    //		while(l<ask[i].l) ans[ask[i].id]+=fxx[l++];
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=a[i]-1;belong[j]==belong[a[i]];j--) sum[j]+=a[i];
    		for(int j=belong[a[i]]-1;j;j--) bsum[j]+=a[i];
    		for(int j=a[i]+1;belong[j]==belong[a[i]];j++) num[j]++;
    		for(int j=belong[a[i]]+1;j<=belong[V];j++) bnum[j]++;
    		for(const Node &x:change[i]){
    			register long long tmp=0;
    			for(int j=x.L;j<=x.R;j++) tmp+=bsum[belong[a[j]]]+sum[a[j]]+a[j]*(bnum[belong[a[j]]]+num[a[j]]);
    			ans[ask[x.i].id]+=x.k*tmp;
    		}
    	}
    	for(int i=1;i<=n;i++) a[i]+=a[i-1];
    	for(int i=1;i<=m;i++) ans[ask[i].id]+=ans[ask[i-1].id];
    	for(int i=1;i<=m;i++) ans[ask[i].id]+=a[ask[i].r]-a[ask[i].l-1];
    	for(int i=1;i<=m;i++) writeEN(ans[i]);
    	return RET;
    }
    
  • 相关阅读:
    模拟google分页效果
    真理胜于一切 JAVA模拟表单提交
    springboot @vaule注解失效解决办法
    安装cnpm
    公众号微信支付开发
    vue去掉链接中的#
    springboot集成mongoDB简易使用
    Spring boot中使用aop详解
    Promise 的基础用法
    MySQL的if,case语句使用总结
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/15903612.html
Copyright © 2020-2023  润新知