Luogu P5332 [JSOI2019]精准预测

Posted tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P5332 [JSOI2019]精准预测相关的知识,希望对你有一定的参考价值。

Link
对于火星人(u),在时间点(t),我们将其拆成两个点((u,t,0),(u,t,1))表示它的存活状态。
考虑用( ext{2-SAT})来表示限制。
那么此时我们有((i,t,0) ightarrow(i,t+1,0),(i,t+1,1) ightarrow(i,t,1))两条边。
对于限制((0,t,u,v)),我们连((u,t,0) ightarrow(v,t+1,0),(v,t+1,1) ightarrow(u,t,1))
对于限制((1,t,u,c)),我们连((u,t,1) ightarrow(v,t,0),(v,t,1) ightarrow(u,t,0))
那么我们要求的就是在选择((u,T+1,0))时有多少个((v,T+1,1))必定被选择,即有多少个((v,T+1,1))((u,T+1,0))的后继中。
注意到对于每个火星人而言,我们可以只保留它的在时刻(T+1)的点和作为(u)限制时的点,那么点数就是(2(n+m))了。
求答案用( ext{bitset})优化( ext{DAG})上传递闭包即可,时空复杂度均为(O(frac{n^2}{omega}))(认为(n,m)同阶)。
空间开不下可以分多次跑。

#include<map>
#include<queue>
#include<bitset>
#include<cctype>
#include<cstdio>
#include<vector>
#include<algorithm>
const int N=300007;
int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
int pos[N],deg[N],ans[N];struct node{int c,t,x,y;}a[N];
std::queue<int>q;std::vector<int>e[N];std::map<int,int>mp[N];std::bitset<10001>s[N],ban;
void add(int c,int u,int v){e[u+c].push_back(v),e[v+1].push_back(u+!c);}
int main()
{
    int t=read(),n=read(),m=read(),cnt=0;
    for(int i=1;i<=m;++i) a[i]={read(),read(),read(),read()},mp[a[i].x][a[i].t]=cnt,cnt+=2;
    for(int i=1;i<=n;++i) mp[i][t+1]=cnt,cnt+=2;
    for(int i=1;i<=m;++i) add(a[i].c,mp[a[i].x][a[i].t],(a[i].c? mp[a[i].y].lower_bound(a[i].t):mp[a[i].y].upper_bound(a[i].t))->second);
    for(int i=1;i<=n;pos[i]=prev(mp[i].end())->second,++i) for(auto l=mp[i].begin(),r=next(l);r!=mp[i].end();l=r,r=next(r)) add(0,l->second,r->second);
    for(int l=1,r;l<=n;l+=10000)
    {
	r=std::min(l+9999,n),ban.reset();
	for(int u=0;u<cnt;++u)
	{
	    s[u].reset();
	    for(int v:e[u]) ++deg[v];
	}
	for(int i=l;i<=r;++i) s[pos[i]+1][i-l]=1;
	for(int u=0;u<cnt;++u) if(!deg[u]) q.push(u);
	for(int u;!q.empty();)
	{
	    u=q.front(),q.pop();
	    for(int v:e[u]) if(s[v]|=s[u],!--deg[v]) q.push(v);
	}
	ban.reset();
	for(int i=l;i<=r;++i) if(s[pos[i]][i-l]) ban[i-l]=1,ans[i]=-1e9;
	for(int i=1;i<=n;++i) ans[i]+=r-l+1-(s[pos[i]]|ban).count();
    }
    for(int i=1;i<=n;++i) printf("%d ",std::max(ans[i]-1,0));
}









以上是关于Luogu P5332 [JSOI2019]精准预测的主要内容,如果未能解决你的问题,请参考以下文章

[Luogu 1197] JSOI2008 星球大战

luogu P1198 [JSOI2008]最大数

[Luogu 1197] JSOI2008 星球大战

luogu_1198 [JSOI2008]最大数

luogu 5505 [JSOI2011]分特产 广义容斥

luogu_1197 [JSOI2008]星球大战

(c)2006-2024 SYSTEM All Rights Reserved IT常识