把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF1718D Permutation for Burenka

题面传送门

首先题目中这个条件相当于笛卡尔树相等。

考虑先建立第一个排列的笛卡尔树,然后把第二个排列的权值放在树上,容易发现每个位置会出一个上界和一个下界。

那么是否每个这种上下界匹配到\(k\)个数中的一个就有解呢?

尝试证明这个条件是充分的,我们发现唯一影响我们判断的其实就是父节点和儿子的大小关系,但是如果父节点小于某个儿子节点,我们可以将父节点与最大的儿子节点互换,因为父节点和儿子节点共用一个上界,而下界父节点一定比儿子节点紧,所以换了之后是成立的,因此条件充分。

然后问题被转化成一个类似于二分图匹配有解性的问题,自然考虑霍尔定理。

根据霍尔定理的形式,最后合法的加进去的一个数显然是一个区间,我们考虑二分区间的左右端点。

假设当前二分出来的值是\(mid\),开一个set维护这个检验过程,有一个显然的贪心:将区间按右端点排序,每次在set中找到最小的可以与这个区间匹配的,并匹配掉。

如果这个区间能匹配掉那是最好,否则考虑第一个无法匹配的区间\([L,R]\)\(mid\)的关系,若\(mid<L\),则说明\(mid\)在最后答案区间的前面,若\(L\leq mid\leq R\)则说明无解,若\(mid>R\)则说明\(mid\)在最后答案区间的后面,根据这个调整二分即可。

然后你写了一发发现TLE on test 11(

瓶颈在于加上set常数的\(O(n\log n\log V)\)看上去不是很可以,因为每次加进去的数是固定的所以考虑用并查集+二分代替这个set,就可以过了。

进一步的,每次二分的位置是固定的,可以提前二分好,复杂度降至\(O(n(\log n+\alpha(n)\log V)\)但是没有上面两个log跑得快

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;using u128=__int128;
using namespace std;const int N=3e5+5,M=4e3+5,K=2e6+5,mod=1e9+7,Mod=mod-1;ll INF=1e9+7;const db eps=1e-5;mt19937 rnd(time(0));
int n,q,k,Ps[N],fa[N],p[N],A[N],P[N],L[N],R[N],Al,Ar,st[N],sh,f[N],H,B[N],x,y,ZJAKIOI,YZXAKIOI;map<int,int> FS;
struct Node{int l,r;}S[N];bool cmp(Node x,Node y){return x.r^y.r?x.r<y.r:x.l<y.l;}
void Make(int x,int La){A[x]&&(La=min(La,A[x]));
	f[x]=A[x];L[x]&&(Make(L[x],La),f[x]=max(f[x],f[L[x]]));R[x]&&(Make(R[x],La),f[x]=max(f[x],f[R[x]]));!A[x]?(S[++H]=(Node){f[x],La},0):(ZJAKIOI|=(A[x]<f[x])||A[x]>La);
}int GF(int x){return fa[x]^x?fa[x]=GF(fa[x]):x;}
int CK(int mid){
	int i,R=1,Fl=0;for(i=1;i<=k;i++) fa[i]=i;for(i=1;i<=H;i++){
		while(R<k&&B[R]<=S[i].r) R++;int p=GF(Ps[i]);
		if((p>=R||B[p]>mid)&&!Fl&&S[i].r>=mid&&mid>=S[i].l) Fl=1;
		else if(p<R) fa[p]=p+1;else return mid<S[i].l?-1:1;
	}return 0;
}
void Solve(){
	ZJAKIOI=0;int i,j;FS.clear();for(i=0;i<=n;i++) L[i]=R[i]=0;st[sh]=0;scanf("%d%d",&n,&q);p[sh=0]=n+1;
	for(i=1;i<=n;i++){scanf("%d",&p[i]);while(sh&&p[i]>p[st[sh]]) sh--;L[i]=R[st[sh]];R[st[sh]]=i;st[++sh]=i;}
	k=0;for(i=1;i<=n;i++) scanf("%d",&A[i]),k+=(!A[i]);H=0;Make(R[0],INF);sort(S+1,S+H+1,cmp);for(i=1;i<k;i++) scanf("%d",&B[i]),ZJAKIOI|=FS.count(B[i]),FS[B[i]]=1;sort(B+1,B+k);
	for(i=1;i<=H;i++) Ps[i]=LB(B+1,B+k,S[i].l)-B;int l=-1,r=1e6+1,mid;while(l+1<r) (CK(mid=l+r>>1)==-1?l:r)=mid;Al=r;l=-1,r=1e6+1,mid;while(l+1<r) (CK(mid=l+r>>1)==1?r:l)=mid;Ar=l;
	while(q--){
		scanf("%d",&x);/*if(!YZXAKIOI)*/ puts(x>=Al&&x<=Ar&&!ZJAKIOI&&!FS.count(x)?"YES":"NO");
		//if((x>=Al&&x<=Ar)^(!CK(x))){for(i=1;i<=n;i++) cout<<A[i]<<' ';cout<<'\n';for(i=1;i<=n;i++) cout<<p[i]<<' ';cout<<'\n';for(i=1;i<k;i++) cout<<B[i]<<' ';cout<<'\n';cout<<x<<'\n';exit(0);} 
	} 
}
int main(){
	freopen("1.in","r",stdin);
	int T;scanf("%d",&T);YZXAKIOI=(T>=200);while(T--) Solve();
}
posted @ 2022-11-18 09:58  275307894a  阅读(32)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end