【題解】「JOISC 2018 Day 3」比太郎的聚會

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

\(\text{Solution:}\)

一定要看好數據範圍!!!

從這題裏面學到了太多……

  • 注意到連邊一定是小點往大點連的,所以一定沒有環

  • 詢問總量是固定的,總輸入量是 \(2\times 10^5\) 級別。

看到這裏起碼可以正常想題了……

首先,如果我們去暴力,那不難想到一個直接從點 \(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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章