• 数据结构训练之四


    https://www.luogu.org/problem/P2824#submit

    做法:

    由于将一个普通序列排序很慢,需要nlogn的时间,所以我们试着把它转化为对01序列排序。先来考虑一个简单的问题:


    • 如何将一个01序列排序?(logn的复杂度)
    • 对于这个问题,我们使用线段树来维护。查询一段区间内的1的个数记为cnt1,如果是升序,就将这段区间的[r-cnt1+1, r]都更改为1,将[l, r-cnt1]更改为0。降序则将[l, l+cnt1-1]更改为1,将[l+cnt, r]更改为0。这样我们就成功地把排序转化为了区间查询和区间修改。

    接下来我们来说本题的做法:

    这是一个离线的做法。首先二分答案mid。我们把原排列中大于等于mid的数都标记为1,小于mid的都标记为0。然后对于每个操作我们就将01序列排个序。最后如果第p个位子仍是1的话就是可行的。

    这个二分成立因为是满足单调性的:可以简单地假设一下,如果你二分的答案是1,那么原序列所有的值都转化为了1,所以最后肯定是true。如果二分一个值成立当且仅当这个位子的值大于等于mid,故如果check返回true,则l = mid+1,否则r = mid-1。

    (这题的思想可以借鉴,比较巧妙)

    code by wzxbeliever:

    #include<bits/stdc++.h>
    #define ll long long
    #define il inline
    #define ri register int
    #define lowbit(x) x&(-x)
    using namespace std;
    const int maxn=1e5+5;
    int n,m,id,ans,mm; 
    int val[maxn],tree[maxn<<2],tag[maxn<<2];
    struct node{
    	int op,LL,RR;
    }Q[maxn];
    il void up(int rt){tree[rt]=tree[rt<<1]+tree[rt<<1|1];return;}
    il void bulid(int l,int r,int rt){
    	if(l==r){tree[rt]=val[l]>=mm;tag[rt]=0;return;}
    	int mid=l+r>>1;
    	bulid(l,mid,rt<<1);
    	bulid(mid+1,r,rt<<1|1);
    	up(rt);tag[rt]=0;//多次记得每次清空 0---->什么也不干 ;1----->赋值为1;2----->赋值为0 
    	return;
    }
    il void modify(int l,int r,int rt,int p){
    	if(!p)return;tag[rt]=p;
    	if(p==1)tree[rt]=r-l+1;
    	else tree[rt]=0; 
    }
    il void down(int l,int r,int rt){
    	if(!tag[rt])return;
    	int mid=l+r>>1;
    	modify(l,mid,rt<<1,tag[rt]);
    	modify(mid+1,r,rt<<1|1,tag[rt]);
    	tag[rt]=0;
    } 
    il int query(int l,int r,int rt,int L,int R){
    	if(L<=l&&r<=R)return tree[rt];
    	int mid=l+r>>1;
    	int tot=0;
    	down(l,r,rt);
    	if(L<=mid)tot+=query(l,mid,rt<<1,L,R);
    	if(mid<R)tot+=query(mid+1,r,rt<<1|1,L,R);
    	return tot;
    }
    il void upd(int l,int r,int rt,int L,int R,int p){
    	if(L<=l&&r<=R){modify(l,r,rt,p);return;}
    	int mid=l+r>>1;
    	down(l,r,rt);
    	if(mid>=L)upd(l,mid,rt<<1,L,R,p);
    	if(mid<R)upd(mid+1,r,rt<<1|1,L,R,p);
    	up(rt);
    }
    il int querypoint(int l,int r,int rt,int pos){
    	if(l==r)return tree[rt];
    	int mid=l+r>>1;
    	down(l,r,rt);
    	if(pos<=mid)return querypoint(l,mid,rt<<1,pos);
    	else return querypoint(mid+1,r,rt<<1|1,pos);
    }
    il bool check(){
    	bulid(1,n,1);
    	for(ri i=1;i<=m;i++){
    		int L=Q[i].LL,R=Q[i].RR;
    		int cnt=query(1,n,1,L,R);
            if(cnt==0)continue;//这个句子很关键,不然会越界re4个点
    		if(Q[i].op==0){
    			upd(1,n,1,L,R-cnt,2);
    			upd(1,n,1,R-cnt+1,R,1);
    		}
    		else {
    			upd(1,n,1,L,L+cnt-1,1);
    			upd(1,n,1,L+cnt,R,2);
    		}
    	}
    	if(querypoint(1,n,1,id)==1)return true;
    	else return false;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(ri i=1;i<=n;i++)scanf("%d",&val[i]);
    	for(ri i=1;i<=m;i++)scanf("%d%d%d",&Q[i].op,&Q[i].LL,&Q[i].RR);
    	scanf("%d",&id);
    	int l=1,r=n;
    	while(l<=r){
    		mm=l+r>>1;
    		if(check())ans=mm,l=mm+1;
    		else r=mm-1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    sql server profiler 对TextData进行过滤
    简单账表"小计"无法正常显示
    从字符串转换日期和/或时间时,转换失败。
    [转载]Java中的final与static的区别
    POI Excel导出样式设置
    [转载]poi 设置Region后单元格边框不起作用
    [转载]将java程序编译成独立运行的exe文件
    Java 线程安全问题—synchronized锁机制
    彻底理解ThreadLocal
    ThreadLocal封装Connection,实现同一线程共享资源
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11748618.html
Copyright © 2020-2023  润新知