~~~~~ P2403 [SDOI2010] 所驼门王的宝藏 ~~~~~ 总题单链接
思路
~~~~~ 这道题的关键在于如何连边。
~~~~~ 对于“横天门”和“纵寰门”建虚点即可。
~~~~~ 对于“任意门”,用一个 vector 存每行有哪些点,然后二分。
~~~~~ 连完边之后缩点,然后 D P DP DP。
~~~~~
c
n
t
:
cnt:
cnt:连通块的数量
~~~~~
d
p
[
i
]
:
dp[i]:
dp[i]: 到第
i
i
i 个连通块最多经过了多少给宝物。
for(ll u=cnt;u>=1;u--){
dp[u]+=siz[u];
for(ll v:ng[u])
dp[v]=max(dp[v],dp[u]);
}
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll Q,n,m,dp[3000005];
ll X[3000005],Y[3000005],T[3000005];
vector<ll>han[1000005],eg[3000005],ng[3000000];
ll stk[3000005],ins[3000005],top;
ll dfn[3000005],low[3000005],tot;
ll pos[3000005],siz[3000005],cnt;
void Tarjan(ll p){
dfn[p]=low[p]=++tot;
stk[++top]=p;ins[p]=1;
for(ll v:eg[p]){
if(!dfn[v]){
Tarjan(v);
low[p]=min(low[p],low[v]);
}
else if(ins[v])low[p]=min(low[p],dfn[v]);
}
if(dfn[p]==low[p]){
cnt++;
while(top){
ll v=stk[top--];
ins[v]=0;
pos[v]=cnt;
if(v<=Q)siz[cnt]++;
if(v==p)break;
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>Q>>n>>m;
for(ll i=1;i<=Q;i++){
cin>>X[i]>>Y[i]>>T[i];
han[X[i]].push_back(i);
eg[X[i]+Q].push_back(i);
eg[Y[i]+Q+n].push_back(i);
if(T[i]==1)eg[i].push_back(X[i]+Q);
if(T[i]==2)eg[i].push_back(Y[i]+Q+n);
}
for(ll i=1;i<=n;i++){
if(han[i].empty())continue;
sort(han[i].begin(),han[i].end(),[&](ll a,ll b){return Y[a]<Y[b];});
}
for(ll i=1;i<=Q;i++){
if(T[i]!=3)continue;
ll U=max(1ll,X[i]-1),D=min(n,X[i]+1);
ll L=max(1ll,Y[i]-1),R=min(m,Y[i]+1);
for(ll x=U;x<=D;x++){
if(han[x].empty())continue;
if(Y[han[x][0]]>R)continue;
if(Y[han[x][han[x].size()-1]]<L)continue;
ll l=0,r=han[x].size()-1,res=0;
while(l<=r){
ll mid=(l+r)>>1;
if(Y[han[x][mid]]>=L)res=mid,r=mid-1;
else l=mid+1;
}
for(ll y=res;y<han[x].size()&&Y[han[x][y]]<=R;y++){
if(i==han[x][y])continue;
eg[i].push_back(han[x][y]);
}
}
}
for(ll i=1;i<=Q+n+m;i++)
if(!dfn[i])Tarjan(i);
for(ll u=1;u<=Q+n+m;u++)
for(ll v:eg[u])
if(pos[u]!=pos[v])
ng[pos[u]].push_back(pos[v]);
for(ll u=cnt;u>=1;u--){
dp[u]+=siz[u];
for(ll v:ng[u])
dp[v]=max(dp[v],dp[u]);
}
ll ans=0;
for(ll i=1;i<=cnt;i++)
ans=max(ans,dp[i]);
cout<<ans;
return 0;
}