其他分享
首页 > 其他分享> > 【题解】「JOISC 2018 Day 3」比太郎的聚会

【题解】「JOISC 2018 Day 3」比太郎的聚会

作者:互联网

「JOISC 2018 Day 3」比太郎的聚会

\(\text{Solution:}\)

一定要看好数据范围!!!

从这题里面学到了太多……

看到这里起码可以正常想题了……

首先,如果我们去暴力,那不难想到一个直接从点 \(x\) 往外暴力扩展的做法。这个做法的时间复杂度是 \(O(n).\)

那么,有没有其他想法?是不是可以预处理一下答案?我们发现如果要预处理的话,至少需要 \(O(n^2)\) 的复杂度。

注意如何预处理:我们需要从小到大枚举点,按照从前到后的顺序,把前面更新过的点维护的点集归并到这个点上,这样复杂度才是最低的。

那么两个做法都过不了,考虑中和一下。

我们可以用预处理的方式处理每个点距离最远的 \(O(\sqrt{n})\) 个点,然后对于询问大于 \(\sqrt{n}\) 的询问,我们发现,输入总量是固定的! 也就是说,这种询问不会超过 \(\sqrt{n}\) 次。

所以综上,我们就可以做到一个 \(O(n\sqrt{n})\) 的解法了。

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,m,Q,in[N],B,qr[N];
typedef pair<int,int> pr;
vector<pr>bk[N];
vector<int>G[N];
inline void link(int x,int y){G[x].push_back(y);}
inline int Max(int x,int y){return x>y?x:y;}
char buf[1<<21],*p1=buf,*p2=buf;
char obuf[1<<21],*O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		s=s*10-'0'+ch;
		ch=getchar();
	}
	return s*w;
}
inline void write(int x){
	if(x<0){
		x=-x;
		*O++='-';
	}
	if(x>9)write(x/10);
	*O++=x%10+'0';
}
#define mk make_pair
#define fi first
#define se second
vector<pr>pv,pu;
int vis[N];
void Do(){
	for(int i=1;i<=n;++i){
		bk[i].push_back(mk(0,i));
		for(int j=0;j<(int)G[i].size();++j){
			int v=G[i][j];
			pv.clear();
			for(int k=0;k<(int)bk[v].size();++k)pv.push_back(mk(bk[v][k].fi+1,bk[v][k].se));
			pu.resize(bk[i].size()+bk[v].size());
			merge(bk[i].begin(),bk[i].end(),pv.begin(),pv.end(),pu.begin(),greater<pr>());
			bk[i].clear();
			for(int k=0;k<pu.size()&&bk[i].size()<B;++k)
				if(!vis[pu[k].se])vis[pu[k].se]=1,bk[i].push_back(pu[k]);
			for(int k=0;k<(int)bk[i].size();++k)vis[bk[i][k].se]=0;
		}
	}
}
int f[N];
int solve(int x){
	for(int i=1;i<=n;++i)f[i]=-(1<<30);
	f[x]=0;
	int ans=-1;
	for(int i=x;i>=1;--i){
		if(!vis[i])ans=Max(ans,f[i]);
		for(int j=0;j<(int)G[i].size();++j)f[G[i][j]]=Max(f[G[i][j]],f[i]+1);
	}
	return ans;
}
int main(){
	n=read();m=read();Q=read();
	for(int i=1;i<=m;++i){
		int u=read(),v=read();
		link(v,u);
	}
	B=320;Do();
	while(Q--){
		int root=read(),num=read();
		for(int i=1;i<=num;++i){qr[i]=read();vis[qr[i]]=1;}
		if(num<B){
			int res=-1;
			for(int i=0;i<(int)bk[root].size();++i){
				if(!vis[bk[root][i].se]){res=bk[root][i].fi;break;}
			}
			write(res);*O++='\n';
		}
		else {
			write(solve(root));
			*O++='\n';
		}
		for(int i=1;i<=num;++i)vis[qr[i]]=0;
	}
	fwrite(obuf,O-obuf,1,stdout);
	return 0;
}

标签:10,int,题解,复杂度,sqrt,JOISC,2018,预处理,define
来源: https://www.cnblogs.com/h-lka/p/15371486.html