zoukankan      html  css  js  c++  java
  • loj#2874. 「JOISC 2014 Day1」历史研究

    题面


    分析

    本题可以作为回滚莫队的入门题。回滚莫队是用于解决一类具有莫队特征、且加删点操作有一个很简单而另一个很难的时候可以使用的算法,复杂度同样为根号级。

    举例而言,本题题意等价于每次询问给定区间,求区间内每个数的值乘以其出现次数之积的最大值。显然,这个问题中加点操作很简单,而朴素的删点需要反复维护次大值,不可做。

    对于这类型的题目,我们可以思考如何尽量执行加点操作而不执行删点操作。可以想到,询问分块后按照区间左端点所在块为第一关键字,右端点为第二关键字排序。

    对于每个询问:

    • 如果左右端点在同一个块内,我们可以暴力计算,复杂度显然是根号。

    • 否则,分别考虑左右端点的处理。对于右端点,由于同块内有序,所以可以直接加点。对于左端点,由于可能无序,所以每次都从块的右端点开始向左端点加点。每个询问的左端点最多可以加根号次,而右端点总共加(n)次,所以最后的复杂度仍然是(nsqrt{n})的。

    于是我们就解决了这类型的问题。需要注意的是,回滚莫队的排序方式影响正确性,而普通莫队的排序只影响时间。

    代码

    /*
    By Nero Claudius Caeser Augustus Germanicus,
    Imperatorum Romanorum.
    */
    #include <bits/stdc++.h>
    
    using namespace std;
    
    namespace StandardIO{
    
    	template<typename T>void read(T &x){
    		x=0;T f=1;char c=getchar();
    		for(; c<'0'||c>'9'; c=getchar()) if(c=='-') f=-1;
    		for(; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
    		x*=f;
    	}
    	template<typename T>void write(T x){
    		if(x<0) putchar('-'),x*=-1;
    		if(x>=10) write(x/10);
    		putchar(x%10+'0');
    	}
    
    } using namespace StandardIO;
    
    namespace Project{
    #define int long long	
    	const int N=100000+100;
    	
    	int n,q,block;
    	int a[N],b[N],belong[N];
    	struct node{
    		int l,r,id;
    		bool operator < (const node x)const{
    			return (belong[l]==belong[x.l])?r<x.r:(belong[l]<belong[x.l]);
    		}
    	} ask[N];
    	int cnt[N],ans[N],ver=1,cnt2[N],res;
    	
    	int calc(int l,int r){
    		int res=0;
    		for(int i=l; i<=r; ++i) cnt2[a[i]]=0;
    		for(int i=l; i<=r; ++i){
    			++cnt2[a[i]];
    			res=max(res,cnt2[a[i]]*b[a[i]]);
    		}
    		return res;
    	}
    	void add(int x){
    		++cnt[a[x]];
    		res=max(res,cnt[a[x]]*b[a[x]]);
    	} 
    	void solve(int x){
    		int rr=min(x*block,n),qr=rr;res=0;
    		memset(cnt,0,sizeof(cnt));
    		while(belong[ask[ver].l]==x){
    			if(belong[ask[ver].l]==belong[ask[ver].r]){
    				ans[ask[ver].id]=calc(ask[ver].l,ask[ver].r),++ver;continue;
    			}
    			while(qr<ask[ver].r) add(++qr);
    			int last=res;
    			for(int i=ask[ver].l; i<=rr; ++i) add(i);
    			ans[ask[ver].id]=res;
    			for(int i=ask[ver].l; i<=rr; ++i) --cnt[a[i]];
    			res=last;
    			++ver;
    		}
    	}
    	
    	void MAIN(){
    		read(n),read(q),block=sqrt(n);
    		for(int i=1; i<=n; ++i){
    			read(a[i]),b[i]=a[i];
    		}
    		sort(b+1,b+n+1);int len=unique(b+1,b+n+1)-b-1;
    		for(int i=1; i<=n; ++i){
    			a[i]=lower_bound(b+1,b+len+1,a[i])-b;
    			belong[i]=(i-1)/block+1;
    		}
    		for(int i=1; i<=q; ++i){
    			read(ask[i].l),read(ask[i].r),ask[i].id=i;
    		}
    		sort(ask+1,ask+q+1);
    		for(int i=1; i<=belong[n]; ++i){
    			solve(i);
    		}
    		for(int i=1; i<=q; ++i){
    			write(ans[i]),puts("");
    		}
    	}
    #undef int 
    }
    
    int main(){ 
    	Project::MAIN();
    }
    
  • 相关阅读:
    elasticsearch 插件 大全
    ElasticSearch 服务搭建
    限制玻尔兹曼机(Restricted Boltzmann Machine)RBM
    卷积神经网络
    [转]MATLAB cell数据类型
    [转]matlab语言中的assert断言函数
    [转]matlab中squeeze函数的用法,numel的用法
    Sparse autoencoder implementation 稀疏自编码器实现
    MATLAB中的randi函数
    可视化自编码器训练结果&稀疏自编码器符号一览表
  • 原文地址:https://www.cnblogs.com/ilverene/p/13417004.html
Copyright © 2011-2022 走看看