[JSOI2019]精准预测(2-SAT+拓扑排序+bitset)

设第i个人在t时刻生/死为(x,0/1,t),然后显然能够连上(x,0,t)->(x,0,t-1),(x,1,t)->(x,1,t+1),然后对于每个限制,用朴素的2-SAT连边即可。

但这样的点数达到了O(nT),其实有一种方法可以只把限制的边连接建图,点数为4m,这样可能会被卡常。

有没有更优秀的做法?当然还是有的。对于2-SAT中的边(x,y),若y在2-SAT中无出边,则x->y与x->y的后继等价,于是点数可以控制在2n+2m。然后很容易发现,生、死状态的图均为拓扑图,而只有生->死的边没有死->生的边,所以原图是拓扑图所以我们的问题变成了对于每一个(x,0,T+1)求出它能够到达的所有(y,1,T+1)的状态数。于是可以topsort+bitset优化,为了能不爆内存,可以分批topsort,每次104个点左右是最好的。

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+7,M=3e5+7;
struct node{int tp,t,x,y;};
int T,n,m,sum[N],ans[N],in[M],q[M],vis[N];
bitset<10000>tmp,b[M];
vector<int>G[M],vec[N];
vector<node>now;
void topsort(int L,int R)
{
    int qs=0,qe=0;
    for(int i=1;i<=2*sum[n];i++)for(int j=0;j<G[i].size();j++)in[G[i][j]]++;
    for(int i=1;i<=2*sum[n];i++)if(!in[i])q[qe++]=i;
    while(qs<qe)
    {
        int u=q[qs++];
        for(int i=0;i<G[u].size();i++)
        {
            b[G[u][i]]|=b[u];
            if(!--in[G[u][i]])q[qe++]=G[u][i];
        }
    }
    tmp.reset();
    for(int i=L;i<=R;i++)if(b[sum[i]][i-L])vis[i]=1,tmp.set(i-L);
    for(int i=1;i<=n;i++)if(!vis[i])ans[i]+=(b[sum[i]]|tmp).count();
}
int main()
{
    scanf("%d%d%d",&T,&n,&m);
    for(int i=1;i<=m;i++)
    {
        node u;scanf("%d%d%d%d",&u.tp,&u.t,&u.x,&u.y),u.tp^=1;
        now.push_back(u),vec[u.x].push_back(u.t);
    }
    for(int i=1;i<=n;i++)
    {
        sort(vec[i].begin(),vec[i].end());
        vec[i].push_back(T+1);
        int t=unique(vec[i].begin(),vec[i].end())-vec[i].begin();
        sum[i]=sum[i-1]+t,vec[i].resize(t);
    }
    for(int i=0;i<now.size();i++)
    {
        int x=now[i].x,y=now[i].y,t=now[i].t;
        int p=lower_bound(vec[x].begin(),vec[x].end(),t)-vec[x].begin()+sum[x-1]+1;
        int q=lower_bound(vec[y].begin(),vec[y].end(),now[i].tp+t)-vec[y].begin()+sum[y-1]+1;
        if(now[i].tp)G[q+sum[n]].push_back(p+sum[n]),G[p].push_back(q);
        else G[q+sum[n]].push_back(p),G[p+sum[n]].push_back(q);
    }
    for(int u=1;u<=n;u++)
    for(int i=sum[u-1]+1;i<sum[u];i++)
    G[i].push_back(i+1),G[i+1+sum[n]].push_back(i+sum[n]);
    for(int i=1;i<=n;i+=10000)
    {
        for(int j=1;j<=2*sum[n];j++)b[j].reset();
        for(int j=0;i+j<=n&&j<10000;j++)b[sum[i+j]+sum[n]].set(j);
        topsort(i,min(n,i+9999));
    }
    for(int i=1;i<=n;i++)printf("%d ",vis[i]?0:n-ans[i]-1);
}

原文地址:https://www.cnblogs.com/hfctf0210/p/10847913.html

时间: 2025-01-08 06:56:27

[JSOI2019]精准预测(2-SAT+拓扑排序+bitset)的相关文章

NOIP 车站分级 (luogu 1983 &amp; codevs 3294 &amp; vijos 1851) - 拓扑排序 - bitset

描述 一条单向的铁路线上,依次有编号为 1, 2, ..., n 的 n 个火车站.每个火车站都有一个级别,最低为 1 级.现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 x,则始发站.终点站之间所有级别大于等于火车站 x 的都必须停靠.(注意:起始站和终点站自然也算作事先已知需要停靠的站点)例如,下表是 5 趟车次的运行情况.其中,前 4 趟车次均满足要求,而第 5 趟车次由于停靠了 3 号火车站(2 级)却未停靠途经的 6 号火车站(亦为 2 级)而不满足要求

CH 2101 - 可达性统计 - [BFS拓扑排序+bitset状压]

题目链接:传送门 描述 给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量.N,M≤30000. 输入格式 第一行两个整数N,M,接下来M行每行两个整数x,y,表示从x到y的一条有向边. 输出格式 共N行,表示每个点能够到达的点的数量. 样例输入 10 10 3 8 2 3 2 5 5 9 5 9 2 3 3 9 4 8 2 10 4 9 样例输出 1 6 3 3 2 1 1 1 1 1 题解: 首先,如果用 $f(x)$ 代表从点 $x$ 出发所能到达的所有点的集合,应有

BZOJ 2109 航空管制(拓扑排序+贪心)

绝世好题啊.. 题意:给出一个DAG,和每个点要求出现在这个DAG里面的拓扑排序的位置<=ti,求出所有可能的拓扑排序里面每个点出现的位置的最小值. 正着做不好做,考虑反着做,建立这个图的反图. 对于一个点出现的位置的最小值,就是n-这个点在反图中出现的位置的最大值. 也就是说拓扑排序时尽量把这个点i排在后面就行了.但是还需要满足一个限制,在反图中这个限制就是每个点在拓扑排序的位置>=n-ti. 于是我们每次拓扑排序从队列中取出点的时候,尽量取n-ti值最小的点,这样就能尽量使得当前处理的点i

贪心+拓扑排序 AOJ 2456 Usoperanto

题目传送门 题意:给出一条链,比如x连到y,x一定要在y的左边,且代价是这条链经过的点的权值和,问如何排序使得代价最小 分析:类似拓扑排序,先把入度为0的点入队,把指向该点的所有点按照权值排序,保证这样是代价是最小的,然后把这一块看成一个点继续入队.看图更简单: /************************************************ * Author :Running_Time * Created Time :2015/10/3 星期六 13:02:41 * File

UVALive - 4255 - Guess (拓扑排序)

Guess 题目传送:Guess 白书例题 注意拓扑排序时,,入度同一时候为0的前缀和须要赋值为同一个数(这个数能够随机取.由于前缀和是累加的,每个a的数值都仅仅和前缀和之差有关).,由于此时能够看成他们的前缀和是相等的,不存在大小关系,,而存在大小关系的都连了一条有向边. .假设此时不赋值为同一个数,,可能对于符号0不是正解.,从而产生错误的结果.. AC代码: #include <map> #include <set> #include <list> #includ

拓扑排序((算法竞赛入门经典)刘汝佳)

转载请注明出处:http://blog.csdn.net/u012860063? viewmode=contents [分析](小白) 把每一个变量看成一个点,"小于"关系看成有向边,则我们得到了一个有向图.这样,我们的任务实际上是把一个图的全部结点排序,使得每一条有向边(u,v)相应的u都排在v的前面.在图论中,这个问题称为拓扑排序. 不难发现:假设图中存在有向环,则不存在拓扑排序,反之则存在.我们把不包括有向环的有向图称为有向无环图.能够借助dfs函数完毕拓扑排序:在訪问完一个结点

拓扑排序(待更新模板)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents ---------------------------------------------------------------------------------------------------------------------------------------------------------- 欢迎光临天资小屋:http://user.qzone.qq.com/593

hdu1285 确定比赛名次(拓扑排序多种方法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1285 Problem Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前.现在请你编程序确定排名. Input 输入有若干组,每组中的第一行为二个数N(1<=N&l

Codeforces Round #290 (Div. 2) 拓扑排序

C. Fox And Names time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Fox Ciel is going to publish a paper on FOCS (Foxes Operated Computer Systems, pronounce: "Fox"). She heard a rumor: t