zoukankan      html  css  js  c++  java
  • [JOISC2014]歴史の研究

    I.[JOISC2014]歴史の研究

    解法1.普通莫队

    普通莫队要保证复杂度是一个根号,须确保插入/删除一个数均是 \(O(1)\),而询问在 \(O(\sqrt n)\) 以内。

    关于本题,最好的分块维护方式,是对一个出现了 \(cnt_x\) 次的元素 \(x\),将 \(1\times x,2\times x,3\times x,\dots,cnt_x\times x\) 全部离散化掉。这样子总离散化元素数量应为 \(\sum cnt_x=n\),可以承受。这样子,需要维护的操作就由修改某个位置的值,变为某个 \(x\) 插入时,插入 \(cnt_x\times x\),出队时删除。可以做到 \(O(1)-O(\sqrt n)\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int BBB=350;
    int n,m,a[100100],lim,buc[100100],BLK[100100],lp[400],cub[100100],CUB[410];
    vector<int>v[100100],u;
    vector<ll>w;
    ll res[100100];
    struct query{
    	int l,r,id;
    	friend bool operator<(const query&u,const query&v){
    		if(u.r/BBB!=v.r/BBB)return u.r/BBB<v.r/BBB;
    		return (u.r/BBB)&1?u.l<v.l:u.l>v.l;
    	}
    }q[100100];
    void Push(int x){
    	x=v[a[x]][buc[a[x]]++];
    	cub[x]++,CUB[BLK[x]]++;
    }
    void Pop(int x){
    	x=v[a[x]][--buc[a[x]]];
    	cub[x]--,CUB[BLK[x]]--;
    }
    ll query(){
    	for(int i=BLK[lim]-1;i>=0;i--){
    		if(!CUB[i])continue;
    		for(int j=lp[i+1]-1;j>=lp[i];j--)if(cub[j])return w[j];
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]),u.push_back(a[i]);
    	sort(u.begin(),u.end()),u.resize(unique(u.begin(),u.end())-u.begin());
    	for(int i=1;i<=n;i++)v[a[i]=lower_bound(u.begin(),u.end(),a[i])-u.begin()+1].push_back(i),w.push_back(1ll*u[a[i]-1]*v[a[i]].size());
    	sort(w.begin(),w.end()),w.resize(lim=unique(w.begin(),w.end())-w.begin());
    	for(int i=1;i<=n;i++)v[a[i]].clear();
    	for(int i=1;i<=n;i++)v[a[i]].push_back(lower_bound(w.begin(),w.end(),1ll*(v[a[i]].size()+1)*u[a[i]-1])-w.begin());
    	for(int i=0;i<lim;i++)BLK[i]=i/BBB;BLK[lim]=BLK[lim-1]+1;
    	for(int i=0;i<=BLK[lim-1];i++)lp[i]=i*BBB;lp[BLK[lim]]=lim;
    	for(int i=1;i<=m;i++)scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
    	sort(q+1,q+m+1);
    	for(int i=1,L=1,R=0;i<=m;i++){
    		while(L>q[i].l)Push(--L);
    		while(R<q[i].r)Push(++R);
    		while(L<q[i].l)Pop(L++);
    		while(R>q[i].r)Pop(R--);
    		res[q[i].id]=query();
    	}
    	for(int i=1;i<=m;i++)printf("%lld\n",res[i]);
    	return 0;
    } 
    

    解法2.回滚莫队

    回滚莫队可以处理一些不方便缩短区间的问题。其流程如下:

    • 询问离线,按照左端点分块,块内询问按照右端点递增排序。这里的块需要显式地建出来
    • 初始令当前处理的区间左端点 \(L=r+1,R=r\),其中 \(r\) 是当前处理块的右端点。
    • 对于右端点未超过块的右端点的询问,显然其长度不会超过 \(\sqrt n\),可以直接暴力。
    • 对于右端点超过块的右端点的询问,可以先右移当前处理的 \(R\) 至询问右端点,然后左移 \(L\) 至左端点,并用回撤数据结构(栈之类)记录。回答询问后,运用回撤数据结构中储存的信息,将 \(L\) 移回 \(r+1\)

    明显复杂度仍是 \(O(n\sqrt n)\)

    要记得清空桶

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int BBB=350;
    typedef long long ll;
    int n,m,a[100100],buc[100100];
    ll mx,res[100100];
    vector<int>v;
    struct query{
    	int l,r,id;
    	query(int L,int R,int ID){l=L,r=R,id=ID;}
    	friend bool operator<(const query&u,const query&v){return u.r<v.r;}
    };
    vector<query>u[410];
    void Push(int x){mx=max(mx,1ll*v[a[x]]*++buc[a[x]]);}
    void Pop(int x){buc[a[x]]--;}
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=0;i<n;i++)scanf("%d",&a[i]),v.push_back(a[i]);
    	sort(v.begin(),v.end()),v.resize(unique(v.begin(),v.end())-v.begin());
    	for(int i=0;i<n;i++)a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin();
    	for(int i=1,l,r;i<=m;i++)scanf("%d%d",&l,&r),l--,r--,u[l/BBB].emplace_back(l,r,i);
    	for(int i=0;i*BBB<n;i++){
    		sort(u[i].begin(),u[i].end());
    		int lim=min(n,(i+1)*BBB);
    		int L=lim,R=L-1;mx=0;
    		for(auto x:u[i]){
    			if(x.r<lim){
    				for(int j=x.l;j<=x.r;j++)Push(j);
    				res[x.id]=mx,mx=0;
    				for(int j=x.l;j<=x.r;j++)Pop(j);
    //				printf("%d\n",x.id);
    				continue;
    			}
    			while(R<x.r)Push(++R);
    			ll tmp=mx;
    			while(L>x.l)Push(--L);
    			res[x.id]=mx,mx=tmp;
    			while(L<lim)Pop(L++);
    		}
    		for(int j=L;j<=R;j++)Pop(j);
    	}
    	for(int i=1;i<=m;i++)printf("%lld\n",res[i]);
    	return 0;
    }
    

  • 相关阅读:
    leetcode 131. Palindrome Partitioning
    leetcode 526. Beautiful Arrangement
    poj 1852 Ants
    leetcode 1219. Path with Maximum Gold
    leetcode 66. Plus One
    leetcode 43. Multiply Strings
    pytorch中torch.narrow()函数
    pytorch中的torch.repeat()函数与numpy.tile()
    leetcode 1051. Height Checker
    leetcode 561. Array Partition I
  • 原文地址:https://www.cnblogs.com/Troverld/p/14620538.html
Copyright © 2011-2022 走看看