zoukankan      html  css  js  c++  java
  • [loj2736][JOISC 2016 Day3]回转寿司——分块+堆

    题目大意:

    给出一个有 (N) 个点的环,环上各点有一个初始权值(a_i)
    给出 (Q) 个询问,每次询问给出一个区间 ([l,r]) 和一个值 (A) ,对于 (A) 的变动定义如下((r) 可能会小于 (l) 因为是环形):

    for (int i = l; i <= r; i++) if(a[i] > A) swap(a[i],A);
    

    对于每个询问,回答遍历完区间 ([l,r])(A) 的最终值。
    注:我们按逆时针方向在环上编号,并规定 ([l,r])为从位置编号为 (l) 的点逆时针遍历至位置编号为 (r) 的点所经过点的集合。

    思路:

    这种看起来怎么都不好做的题目考虑分块。
    对于这个操作,我们对于每一块显然只需要取出其中最大的元素即可,用一个堆来维护每一个块的中的元素。
    但是对于边角块,修改的时候可以暴力修改,可我们也需要知道每一个元素的具体位置,于是这里有了一种重构的操作:
    我们将每一次放入这个块内的元素记录下来,按照从小到大的顺序进行那种交换的操作,只考虑最终的结果,不难发现这样是正确的,用一个小根堆维护即可。
    时间复杂度(Theta(nsqrt {n}log n))

    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<endl
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("in.in","r",stdin);
    	freopen("in.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	T __=0,mul=1; char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')mul=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    	_=__*mul;
    }
    
    const int maxn=4e5+10;
    const int maxb=800+10;
    const int B=600;
    int n,q,a[maxn],bel[maxn],L[maxb],R[maxb];
    priority_queue<int>big[maxb];
    priority_queue<int,vector<int>,greater<int> >small[maxb];
    
    void rebuild(int id){
    	if(small[id].empty())return;
    	REP(i,L[id],R[id]){
    		if(a[i]>small[id].top()){
    			int t=small[id].top();
    			small[id].pop();
    			small[id].push(a[i]);
    			a[i]=t;
    		}
    	}
    	while(!small[id].empty())small[id].pop();
    }
    
    int modify_block(int l,int r,int x){
    	int id=bel[l];
    	REP(i,l,r)if(a[i]>x)swap(x,a[i]);
    	while(!big[id].empty())big[id].pop();
    	REP(i,L[id],R[id])big[id].push(a[i]);
    	//REP(i,L[id],R[id])cout<<a[i]<<" ";
    	//cout<<endl;
    	return x;
    }
    
    int modify(int l,int r,int x){
    	//debug(l); debug(r);
    	int bl=bel[l],br=bel[r],t;
    	rebuild(bel[l]); rebuild(bel[r]);
    	if(bl==br)return modify_block(l,r,x);
    	else{
    		x=modify_block(l,R[bl],x);
    		REP(i,bl+1,br-1)if(big[i].top()>x){
    			t=big[i].top(); big[i].pop();
    			big[i].push(x); small[i].push(x);
    			x=t;
    		}
    		return modify_block(L[br],r,x);
    	}
    }
    
    void init(){
    	read(n); read(q);
    	REP(i,1,n)read(a[i]);
    
    	memset(L,63,sizeof(L));
    	memset(R,-1,sizeof(R));
    	REP(i,1,n){
    		bel[i]=(i-1)/B+1;
    		L[bel[i]]=min(L[bel[i]],i);
    		R[bel[i]]=max(R[bel[i]],i);
    	}
    
    	REP(i,1,n)big[bel[i]].push(a[i]);
    }
    
    void work(){
    	int l,r,x;
    	REP(i,1,q){
    		read(l),read(r),read(x);
    		if(l<=r)printf("%d
    ",modify(l,r,x));
    		else printf("%d
    ",modify(1,r,modify(l,n,x)));
    	}
    }
    
    int main(){
    	//File();
    	init();
    	work();
    	return 0;
    }
    
  • 相关阅读:
    oracle调用存储过程和函数返回结果集
    怎样让Oracle的存储过程返回结果集
    Java 调用存储过程 返回结果集
    oracle多表关联删除数据表记录方法
    ORACLE多表关联UPDATE 语句
    Oracle--用户管理与权限分配
    java代码开启关闭线程(nginx)
    netty实现websocket客户端(附:测试服务端代码)
    netty同时实现http与socket
    Oracle-控制语句
  • 原文地址:https://www.cnblogs.com/ylsoi/p/9845778.html
Copyright © 2011-2022 走看看