版本0:差分,差分没办法解决样例1
版本1:拓扑
建图,从级别低的车站流向级别高的车站
版本2:用线段树优化拓扑
就是将区间缩成点了,详情见代码
拓扑排序
#include
using namespace std;
typedef pair<int,int> pii;
const int N=1e3+10;
bool vis[N];//判断是否停靠
vector<int>g[N];
int n,m,k;
int d[N];//入度
int cnt=0;
int s[N];
bool mp[N][N];//建图 防止重边
int tp(){
//先搜完级别低的
int ans=1;
queue<pii>q;
for (int i = 1; i <= n; ++i) {
if(!d[i])q.push({i,1});//车站 级别
}
while(q.size()){
int u=q.front().first;
int t=q.front().second;
q.pop();
for (int i = 0; i <g[u].size(); ++i) {
int v=g[u][i];
d[v]--;
if(!d[v]){
ans=max(ans,t+1);
q.push({v,t+1});
}
}
}
return ans;
}
int main(){
cin>>n>>m;
for (int i = 1; i <= m; ++i) {
cin>>cnt;//停靠的车站的个数
memset(vis, false, sizeof(vis));
for (int j = 1; j <= cnt; ++j) {
cin>>s[j];
vis[s[j]]= true;
}
//建图
for (int j = s[1]; j <= s[cnt]; ++j) {
//枚举从起点到终点所有不停靠的车站
if(vis[j])continue;
//车站中间的点的级别低于停靠车站 外层级别低的车站
for (int k = 1; k <= cnt; ++k) {//内层级别高的车站
if(!mp[j][s[k]]){
mp[j][s[k]]=true;
g[j].push_back(s[k]);//级别低的点到级别高的点
d[s[k]]++;
}
}
}
}
cout <<tp() << endl;
return 0;
}
线段树、虚拟点优化后的
#include
using namespace std;
const int N=1e6+10;
int n,m,k;
struct edge{
int next,to;
}e[N];
int head[N],tot;
int d[N];//入度
void add(int u,int v){//级别低u流向级别高v
d[v]++;
e[++tot]={head[u],v};
head[u]=tot;
}
int num[N];//存点i所在的根节点rt
int dis[N];//到达当前节点的消耗的权值 注意这个数组
int tp;//根节点
void build(int l,int r,int rt){
tp=max(tp,rt);//找到最后一个根节点
if(l==r){
dis[rt]=1;
num[l]=rt;
return;
}
int mid=l+r>>1;
add(rt<<1,rt);//连接根节点
build(l,mid,rt<<1);
add(rt<<1|1,rt);
build(mid+1,r,rt<<1|1);
}
void update(int l,int r,int rt,int x,int y,int tmp){
if(x<=l && r<=y){
add(rt,tmp);//级别低的节点(区间)流向级别高的节点
return;
}
int mid=l+r>>1;
if(x<=mid) update(l,mid,rt<<1,x,y,tmp);
if(mid<y) update(mid+1,r,rt<<1|1,x,y,tmp);
}
int ans=1;
int dep[N];//级别 或者说 深度
queue<int>q;
void bfs(){
for (int i = 1; i <= tp; ++i) {
if(!d[i]) {
q.push(i);
dep[i]=dis[i];//虚拟节点dep[]=dis[]=0
}
}
while(q.size()){
int u=q.front();
q.pop();
for (int i = head[u]; i ; i=e[i].next) {
int v=e[i].to;
dep[v]=max(dep[v],dep[u]+dis[v]);//有些节点dis[v]=0 as:tp>n的那些rt节点 所以直接复制上层级别
ans=max(ans,dep[v]);
if(!(--d[v]))q.push(v);
}
}
}
int cnt;
int st[N];
int main(){
cin>>n>>m;
build(1,n,1);//建树
for (int i = 1; i <= m; ++i) {
cin>>cnt;
tp++;//最后一个根节点 设置虚拟节点 dis[tp]=0;
for (int j = 1; j <= cnt; ++j) {
cin>>st[j];
}
for (int j = 1; j < cnt; ++j) {
add(tp,num[st[j]]);//直接流向叶子节点
if(st[j]+1<=st[j+1]-1)//更新中间级别低的区间
update(1,n,1,st[j]+1,st[j+1]-1,tp);
}
add(tp,num[st[cnt]]);
}
bfs();
cout<<ans<<endl;
return 0;
}