zoukankan      html  css  js  c++  java
  • P6829 [IOI2020]植物比较

    P6829 [IOI2020]植物比较

    听WC2021的时候听到了这道题,然后就来做了。

    大概思路就是处理出一个类似拓扑序的东西。如果一个数后面 (k) 个数中比它大的数都已经扩展过了,那么就扩展它。

    每次取出一个 (0) 扩展,用线段树区间减动态来维护每个数后面比它小的数的个数(有多个 (0) 取哪个并不那么容易解决,后面会讲)。

    这样可以保证下标差 (<k) 的两个数可以通过比较拓扑序大小来比较大小,即拓扑序小的更大。

    所以,如果两个数大小关系确定,那么就比较拓扑序(后文写作 (tpn))。否则返回 (0)

    考虑如何判断能否判定大小关系。

    不妨 (tpn_a<tpn_b) ,那么从 (a) 开始,不断往更大的 (tpn) 跳,同时维持大小的确定性,如果能跳到 (b) ,那么就可以判定大小关系。

    维持大小确定性只需要不断往下标差 (<k) 的区域跳即可。

    可以处理出每个数往左 (k) 个数中 (tpn) 最小的比 (a) 拓扑序大的点,跳到不能跳为止,显然倍增优化一下。往右也要扩展一次。

    这个可以按照 (tpn) 从大到小加入位置,用线段树维护区间最小值解决。

    如果两次至少有一次区域包含了 (b) 那么就可以确定大小关系。

    然而在实现的时候我遇上的最大的问题是在预处理拓扑序。

    如果出现多个 (0) ,该取哪个?

    直接取下标最小的必然是错的。

    考虑如下数据: ( m{r=[1,0,1,0,0],k=3})

    一开始应该找的拓扑序最小的点不应该是 (2) 。因为 (r_5) 后面三个数,也就是 ([r_5,r_1,r_2]) ,没有大于 (r_5) 的,说明 (r_1<r_5)

    同理,如果找 (5) ,发现 (r_4) 后面三个数中间没有大于 (r_4) 的,所以 (r_4>r_5)

    问题应该很明确了:先找到一个 (0) ,如果它左边 (k) 个之内有 (0),那么优先取左边的那个。

    剩下就全是实现的问题了。

    考虑多开一颗线段树维护所有 (0) 的位置,对于每一个区间维护:最靠左的 (0) ,最靠右的 (0) ,区间相邻的 (0) 的最大距离。

    同时在原来维护区间减的线段树维护区间最靠前的 (0) 的位置,区间最小值。

    处理的拓扑序的时候,先在原来的线段树查询出最靠左的 (0) 的位置。

    如果它可以扩展到 (n) (从环的另一端绕),那么再在第二颗线段树上二分端点最靠左的合法后缀,这样子就能找到我们需要的位置了!

    复杂度 (O(nlog n))提交记录

    #include"plants.h"
    #include<bits/stdc++.h>
    using namespace std;
    
    #define fi first
    #define se second
    #define pb push_back
    #define mkp make_pair
    #define sz(v) (int)(v).size()
    template<class T>inline bool ckmax(T&x,T y){return x<y?x=y,1:0;}
    template<class T>inline bool ckmin(T&x,T y){return x>y?x=y,1:0;}
    #define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
    #define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
    typedef long long LL;
    
    const int N=200005;
    const int T=N<<2;
    const int inf=0x3f3f3f3f;
    int n,a[N],tpn[N],tpo,len;
    int L[20][N],R[20][N];
    LL dl[20][N],dr[20][N];
    vector<int>v0;
    
    namespace sg1{
    int miv[T],tag[T],id[T];
    #define lc (p<<1)
    #define rc (p<<1|1)
    void pushup(int p){
    	miv[p]=inf,id[p]=0;
    	if(ckmin(miv[p],miv[lc]))id[p]=id[lc];
    	if(ckmin(miv[p],miv[rc]))id[p]=id[rc];
    }
    void build(int l,int r,int p,int*a){
    	tag[p]=0,miv[p]=inf;
    	if(l==r)return miv[p]=a[l],id[p]=l,void();
    	int mid=(l+r)>>1;
    	build(l,mid,lc,a),build(mid+1,r,rc,a);
    	pushup(p);
    }
    void pushdown(int p){
    	if(tag[p]){
    		tag[lc]+=tag[p],miv[lc]+=tag[p];
    		tag[rc]+=tag[p],miv[rc]+=tag[p];
    		tag[p]=0;
    	}
    }
    void get0(int p,int l,int r){
    	if(l==r)return v0.pb(l),void();
    	pushdown(p);
    	int mid=(l+r)>>1;
    	if(!miv[lc])get0(lc,l,mid);
    	if(!miv[rc])get0(rc,mid+1,r);
    }
    void update(int ql,int qr,int d,int l=1,int r=n,int p=1){
    	if(ql>qr)return;
    	if(ql<=l&&r<=qr){
    		miv[p]+=d,tag[p]+=d;
    		if(!miv[p])get0(p,l,r);
    		return;
    	}
    	pushdown(p);
    	int mid=(l+r)>>1;
    	if(ql<=mid)update(ql,qr,d,l,mid,lc);
    	if(mid<qr)update(ql,qr,d,mid+1,r,rc);
    	pushup(p);
    }
    void change(int pos,int d,int l=1,int r=n,int p=1){
    	if(l==r)return miv[p]=d,void();
    	int mid=(l+r)>>1;
    	if(pos<=mid)change(pos,d,l,mid,lc);
    	else change(pos,d,mid+1,r,rc);
    	pushup(p);
    }
    pair<int,int>query(int ql,int qr,int l=1,int r=n,int p=1){
    	if(ql>qr)return mkp(inf,inf);
    	if(ql<=l&&r<=qr)return mkp(miv[p],id[p]);
    	int mid=(l+r)>>1;pair<int,int>res=mkp(inf,inf);
    	if(ql<=mid)ckmin(res,query(ql,qr,l,mid,lc));
    	if(mid<qr)ckmin(res,query(ql,qr,mid+1,r,rc));
    	return res;
    }
    #undef lc
    #undef rc
    }
    
    namespace sg2{
    #define lc (p<<1)
    #define rc (p<<1|1)
    int sv[T],sl[T],sr[T];
    void pushup(int p){
    	if(sl[lc])sl[p]=sl[lc];
    	else sl[p]=sl[rc];
    	if(sr[rc])sr[p]=sr[rc];
    	else sr[p]=sr[lc];
    	sv[p]=max(sv[lc],sv[rc]);
    	if(sl[rc]&&sr[lc])ckmax(sv[p],sl[rc]-sr[lc]);
    }
    void change(int pos,int k,int l=1,int r=n,int p=1){
    	if(l==r){
    		sl[p]=sr[p]=k?l:0;
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(pos<=mid)change(pos,k,l,mid,lc);
    	else change(pos,k,mid+1,r,rc);
    	pushup(p);
    }
    int query(int l=1,int r=n,int p=1){
    	if(l==r)return l;
    	int mid=(l+r)>>1;
    	if(!sl[rc])return query(l,mid,lc);
    	if(!sl[lc])return query(mid+1,r,rc);
    	if(sv[rc]<len&&sl[rc]-sr[lc]<len)return query(l,mid,lc);
    	return query(mid+1,r,rc);
    }
    
    #undef lc
    #undef rc
    }
    
    int dis(int x,int y){
    	return x<=y?y-x:y+n-x;
    }
    int compare_plants(int a,int b){
    	++a,++b;
    	int flg=1;
    	if(tpn[a]>tpn[b])flg=-1,swap(a,b);
    	LL dst=0;int u=a;
    	for(int i=19;i>=0;--i)
    		if(L[i][u]&&tpn[L[i][u]]<=tpn[b])dst+=dl[i][u],u=L[i][u];
    	if(dst>=dis(b,a))return flg;
    	dst=0,u=a;
    	for(int i=19;i>=0;--i)
    		if(R[i][u]&&tpn[R[i][u]]<=tpn[b])dst+=dr[i][u],u=R[i][u];
    	if(dst>=dis(a,b))return flg;
    	return 0;
    }
    inline bool cmp(const int&a,const int&b){
    	return tpn[a]>tpn[b];
    }
    void init(int k,std::vector<int>r){
    	len=k,n=r.size(),tpo=0;
    	for(int i=0;i<n;++i)a[i+1]=r[i];
    	sg1::build(1,n,1,a);
    	for(int i=1;i<=n;++i)if(!a[i])sg2::change(i,1);
    	for(int i=1;i<=n;++i){
    		int x=sg1::id[1];
    		if(x-k+1<1){
    			pair<int,int>tmp=sg1::query(n+x-k+1,n);
    			if(!tmp.fi)x=sg2::query();
    		}
    		tpn[x]=++tpo;
    		sg1::change(x,inf),sg2::change(x,0);
    		v0.clear();
    		sg1::update(max(1,x-k+1),x,-1);
    		if(x-k+1<1)sg1::update(n+x-k+1,n,-1);
    		for(int j:v0)sg2::change(j,1);
    	}
    	for(int i=1;i<=n;++i)a[i]=inf;
    	sg1::build(1,n,1,a);
    	for(int i=1;i<=n;++i)a[i]=i;
    	sort(a+1,a+n+1,cmp);
    	for(int i=1;i<=n;++i){
    		int x=a[i],le=0,ri=0;
    		pair<int,int>tl=sg1::query(max(1,x-k+1),x);
    		if(tl.fi<inf)le=tl.se;
    		if(x-k+1<1){
    			pair<int,int>ttl=sg1::query(n+x-k+1,n);
    			if(tl.fi>ttl.fi)le=ttl.se;
    		}
    		pair<int,int>tr=sg1::query(x,min(x+k-1,n));
    		if(tr.fi<inf)ri=tr.se;
    		if(x+k-1>n){
    			pair<int,int>ttr=sg1::query(1,x+k-1-n);
    			if(tr.fi>ttr.fi)ri=ttr.se;
    		}
    		sg1::change(x,tpn[x]);
    		L[0][x]=le,R[0][x]=ri;
    		dl[0][x]=dis(le,x),dr[0][x]=dis(x,ri);
    	}
    	for(int i=1;i<=19;++i)
    		for(int j=1;j<=n;++j)
    			L[i][j]=L[i-1][L[i-1][j]],R[i][j]=R[i-1][R[i-1][j]],
    			dl[i][j]=dl[i-1][j]+dl[i-1][L[i-1][j]],
    			dr[i][j]=dr[i-1][j]+dr[i-1][R[i-1][j]];
    }
    
    
    路漫漫其修远兮,吾将上下而求索
  • 相关阅读:
    webpack实现开发、测试、生产等环境的打包切换
    Python报错
    WGAN将数值限制在一定范围内 Python代码 tf.clip_by_value(p, -0.01, 0.01))
    cmd 进入指定文件夹
    Wasserstein 距离
    MSE(均方误差)、RMSE (均方根误差)、MAE (平均绝对误差)
    inf
    plt画log图
    KL散度与JS散度
    安装指定版本的第三方包
  • 原文地址:https://www.cnblogs.com/zzctommy/p/14373480.html
Copyright © 2011-2022 走看看