【题解】「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;
}
标签:10,int,题解,复杂度,sqrt,JOISC,2018,预处理,define 来源: https://www.cnblogs.com/h-lka/p/15371486.html