https://www.zybuluo.com/ysner/note/1252538

题面

有一个数列\(\{a\}\)。现给定多组限制,限制分成\(2\)类,第一类是\(a_x+1=a_y\),有\(m_1\)个; 第二类是\(a_x\leq a_y\),有\(m_2\)个。求这些数最多有多少种不同的取值。

  • \(n\leq600,m_1+m_2\leq10^5\)

解析

看到不等式就可以想到差分约束。

根据一些差分约束小常识,可以设\(dis[x][y]\)表示\(a_x\)最多能比\(a_y\)大多少。

于是对第一类,\(dis[x][y]=1,dis[y][x]=-1\)。(双向边适用于定量比较)

第二类,由于是\(a_y\geq a_x\),\(dis[y][x]=0\)。(单向边适用于定性比较)

一般来说,图中只要有非\(0\)环就是不合法的。

观察一下建边,可以发现如果有正环,它的反边就会构成负环。

于是只要判负环就可以了。

如何判负环?

\(SPFA\)判负环(初始化一定要为正无穷)、\(floyd\)判断\(dis[i][i]<0\)都可以。

然而这题用前者会出现点小坑。

因为我们一般出发都会以\(1\)为起点,而这一个图中\(1\)不一定与负环联通。

怎么办?

跑\(tarjan\)找出联通块。虚构一个结点,与各个联通块建边权为\(0\)的边(主要注意防止因该结点的建立而产生新的负环),然后从虚构点出发\(SPFA\)即可。

缩完点后,图中只剩边权为\(0\)的边连接各联通块(第一类自己就能构成一个块)。由于“大于等于”这个关系不限制绝对大小,因而对答案没有影响(因可以无限扩大自己的值),可以忽略这些边。

于是各联通块内\(maxdis+1\)之和即为答案。

(话说只在联通块内跑\(floyd\)的效率真是恐怖,\(SPFA\)判负环成了复杂度瓶颈)

完了?然而还要注意限制条件可以叠加,所以要取\(\min\)。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int mod=1e9+7,N=605;
struct Edge{int to,nxt,w;}e[N*400];
int n,m1,m2,h[N],cnt,dis[N],dfn[N],low[N],tim,sta[N],top,scc,bl[N],sz[N],num[N],d[N][N];
bool vis[N];
ll ans;
queue<int>Q;
il void add(re int u,re int v,re int w){e[++cnt]=(Edge){v,h[u],w};h[u]=cnt;}
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void tarjan(re int u)
{
dfn[u]=low[u]=++tim;vis[u]=1;sta[++top]=u;
re int v;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
else if(vis[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
++scc;
do{v=sta[top];bl[v]=scc;vis[v]=0;++sz[scc];top--;}while(u^v);
}
}
il int fSPFA(re int st)
{
memset(dis,63,sizeof(dis));memset(vis,0,sizeof(vis));memset(num,0,sizeof(num));
while(!Q.empty()) Q.pop();
dis[st]=0;num[st]=1;Q.push(st);vis[st]=1;
while(!Q.empty())
{
re int u=Q.front();Q.pop();
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(dis[v]>dis[u]+e[i].w)
{
if((++num[v])>n) return 0;
dis[v]=dis[u]+e[i].w;
if(!vis[v]) vis[v]=1,Q.push(v);
}
}
vis[u]=0;
}
return 1;
}
int main()
{
memset(h,-1,sizeof(h));memset(d,63,sizeof(d));
re int u,v;
n=gi();m1=gi();m2=gi();
fp(i,1,m1) u=gi(),v=gi(),add(u,v,1),add(v,u,-1),d[u][v]=min(d[u][v],1),d[v][u]=min(d[v][u],-1);
fp(i,1,m2) u=gi(),v=gi(),add(v,u,0),d[v][u]=min(d[v][u],0);
fp(i,1,n) d[i][i]=min(d[i][i],0);
fp(i,1,n) if(!dfn[i]) tarjan(i);
memset(vis,0,sizeof(vis));
fp(i,2,n)
if(!vis[bl[i]])
add(0,i,0),vis[bl[i]]=1;
memset(vis,0,sizeof(vis));
//if(!fSPFA(0)) {puts("NIE");return 0;}
fp(o,1,scc)
{
re ll mx=0;
fp(k,1,n)
{
if(bl[k]!=o) continue;
fp(i,1,n)
{
if(bl[i]!=o||d[i][k]==d[0][0]) continue;
fp(j,1,n)
{
if(bl[j]!=o||d[k][j]==d[0][0]) continue;
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
fp(i,1,n)
{
if(bl[i]!=o) continue;
fp(j,1,n)
{
if(bl[j]!=o) continue;
mx=max(mx,d[i][j]);
}
}
ans+=mx+1;
}
fp(i,1,n) if(d[i][i]<0) {puts("NIE");return 0;}
printf("%lld\n",ans);
return 0;
}

[POI2012]FES-Festival的更多相关文章

  1. [BZOJ2788][Poi2012]Festival

    2788: [Poi2012]Festival Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 187  Solved: 91[Submit][Statu ...

  2. [Poi2012]Festival 题解

    [Poi2012]Festival 时间限制: 1 Sec  内存限制: 64 MB 题目描述 有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类: 1. 给出a,b (1 ...

  3. [Poi2012]Festival 差分约束+tarjan

    差分约束建图,发现要在每个联通块里求最长路,600,直接O(n3) floyed #include<cstdio> #include<cstring> #include< ...

  4. [POI2012]Festival

    题目大意: 有$n$个正整数$x_1,x_2,\ldots,x_n$,再给出一些限制条件,限制条件分为两类: 1.给出$A,B$,要求满足$X_A+1=X_B$: 2.给出$C,D$,要求满足$X_C ...

  5. bzoj 2788 [Poi2012]Festival 差分约束+tarjan+floyd

    题目大意 有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类: 1.给出a,b (1<=a,b<=n),要求满足Xa + 1 = Xb 2.给出c,d (1&l ...

  6. POI2012题解

    POI2012题解 这次的完整的\(17\)道题哟. [BZOJ2788][Poi2012]Festival 很显然可以差分约束建图.这里问的是变量最多有多少种不同的取值. 我们知道,在同一个强连通分 ...

  7. 2795: [Poi2012]A Horrible Poem

    2795: [Poi2012]A Horrible Poem Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 484  Solved: 235[Subm ...

  8. [BZOJ2803][Poi2012]Prefixuffix

    2803: [Poi2012]Prefixuffix Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 219  Solved: 95[Submit][St ...

  9. [BZOJ2799][Poi2012]Salaries

    2799: [Poi2012]Salaries Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 91  Solved: 54[Submit][Statu ...

  10. [BZOJ2797][Poi2012]Squarks

    2797: [Poi2012]Squarks Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 211  Solved: 89[Submit][Status ...

随机推荐

  1. Django之ORM操作(***)

    Django之ORM操作(***) http请求的流程: url--> 视图view(模板+数据库) --> ORM的功能: 可以转换SQL语句,并做操作. ORM操作数据表: -创建表: ...

  2. 慕课笔记利用css进行布局【两列布局】

    <html> <head> <title>两列布局</title> <style type="text/css"> bo ...

  3. HDU 2647 逆向拓扑排序

    令每一个员工都有一个自己的等级level[i] , 员工等级越高,那么工资越高,为了使发的钱尽可能少,所以每一级只增加一单位的钱 输入a b表示a等级高于b,那么我们反向添加边,令b—>a那么i ...

  4. 开发辅助网站---programcreek

    开发中让我们事半功倍的工具网站,开发中经常遇到api如何使用,很好的解决这个问题.java代码api案例网,提供最简单的demo,很不错分享一下,大家可以用用. http://www.programc ...

  5. 何为幻读?MySQL又是如何解决幻读的?

    一.什么是幻读 在一次事务里面,多次查询之后,查询的结果集的个数不一致的情况叫做幻读.而多出来或者少的哪一行被叫做 幻行 二.为什么要解决幻读 在高并发数据库系统中,需要保证事务与事务之间的隔离性,还 ...

  6. hadoop(1)入门

    hadoop入门(一)   一.概述 1.什么是hadoop hadoop不仅是一个用于存储分布式文件系统,还是设计用来在有通用计算设备组成的大型集群上执行的分布式应用的基础框架. hadoop框架最 ...

  7. dtrace.org

    http://dtrace.org/blogs/rm/2016/09/15/turtles-on-the-wire-understanding-how-the-os-uses-the-modern-n ...

  8. spark开发环境配置

    以后spark,mapreduce,mpi可能三者集于同一平台,各自的侧重点有所不用,相当于云计算与高性能计算的集合,互补,把spark的基础看了看,现在把开发环境看看,主要是看源码,最近Apache ...

  9. Java 代理模式和装饰者模式的区别

    装饰模式:以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案:代理模式:给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用: 装饰模式应该为所装饰的对象增强功能:代理模式对代理的 ...

  10. 在HTML中显示图片时希望如果图片不存在或者无法显示时,能够显示默认图片

    很多时候,在HTML中显示图片时希望如果图片不存在或者无法显示时,能够显示默认图片.可以通过以下方式: <img src="xxx.jpg" onError="th ...