O(qlogn)求条
查看原帖
O(qlogn)求条
1066579
XP3301_Pipi楼主2024/3/12 18:45

rt,我的思路就是每次找两个序列(设拼接后长度是k)的第k/2小的数,每次砍掉k/2个数,但是TLE ON #11 只要对代码有帮助的都会关注

#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
#define pll pair<ll,ll>
using namespace std;
const int N=1e6+15;
const long long INF=0x3f3f3f3f3f3f3f3fll;

inline void FileIO(){
	freopen("Latent.in","r",stdin);
	freopen("Latent.out","w",stdout);
}

template<typename Type>
inline void read(Type& res){
	Type x=0,f=1; char c=' '; while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
	res=x*f;
}

int T,n,q;
vector<ll> a[N];

ll Solve(vector<ll> x,int s1,int t1,vector<ll> y,int s2,int t2,int k){
//	vector<ll> x=a[xx],y=a[yy];
//	printf("Solve: s1=%d,t1=%d,s2=%d,t2=%d,k=%d\n",s1,t1,s2,t2,k);
//	if(t1-s1+1>t2-s2+1) return Solve(yy,s2,t2,xx,s1,t1,k);
	if(t1-s1+1==0) return y[s2+k-1];
	if(t2-s2+1==0) return x[s1+k-1];
	if(k==1) return min(x[s1],y[s2]);
	int pos1=min(t1,s1+k/2-1);
	int pos2=min(t2,s2+k/2-1);
//	printf("Pos1=%d Pos2=%d\n",pos1,pos2);
	if(x[pos1]<y[pos2]) return Solve(x,pos1+1,t1,y,s2,t2,k-(pos1-s1+1));
	else return Solve(x,s1,t1,y,pos2+1,t2,k-(pos2-s2+1));
}

ll Midian(int xx,int yy){
	vector<ll> x=a[xx],y=a[yy];
	int k=(x.size()+y.size()+1)/2;
//	printf("x.size=%d y=size=%d\n",x.size(),y.size());
	return Solve(x,0,x.size()-1,y,0,y.size()-1,k);
}

signed main(){
//	不开longlong见祖宗!
//	检查数组大小!
//	禁止在int乘int时不开longlong!
	//FileIO();
	read(T);
	while(T--){
		for(int i=1;i<=n;i++) a[i].clear();
		read(n),read(q);
		int k;
		for(int i=1;i<=n;i++){
			read(k); ll tmp;
			for(int j=1;j<=k;j++){
				read(tmp);
				a[i].push_back(tmp);
			}
			sort(a[i].begin(),a[i].end());
		}
		int x,y; ll res;
		while(q--){
			read(x),read(y);
			res=Midian(x,y);
			printf("%lld\n",res);
		}
	}
	return 0;
}
2024/3/12 18:45
加载中...