码迷,mamicode.com
首页 > Web开发 > 详细

Luogu P5332 [JSOI2019]精准预测

时间:2020-05-21 22:29:45      阅读:68      评论:0      收藏:0      [点我收藏+]

标签:link   getchar   main   ext   row   amp   保留   优化   while   

Link
对于火星人\(u\),在时间点\(t\),我们将其拆成两个点\((u,t,0),(u,t,1)\)表示它的存活状态。
考虑用\(\text{2-SAT}\)来表示限制。
那么此时我们有\((i,t,0)\rightarrow(i,t+1,0),(i,t+1,1)\rightarrow(i,t,1)\)两条边。
对于限制\((0,t,u,v)\),我们连\((u,t,0)\rightarrow(v,t+1,0),(v,t+1,1)\rightarrow(u,t,1)\)
对于限制\((1,t,u,c)\),我们连\((u,t,1)\rightarrow(v,t,0),(v,t,1)\rightarrow(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)\)了。
求答案用\(\text{bitset}\)优化\(\text{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]精准预测

标签:link   getchar   main   ext   row   amp   保留   优化   while   

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12933959.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!