zoukankan      html  css  js  c++  java
  • [luogu3573]RAJ-Rally

    先建一个$S$和$T$,$forall 1le ile n$连边$(S,i)$和$(i,T)$,则最长路即为$S到T的最长路-2$

    对于这张DAG,求出一个拓扑序,点$i$为第$i$个(特别的,$id_{S}=0$且$id_{T}=n+1$),根据拓扑序的性质,对于一条路径,其$id$必然单调递增

    枚举删除的点$k$,再枚举$S$到$T$的最长路上$id$中$k$的前驱后继(由于$S$和$T$,因此必然存在,强制不等于$k$),记作$i$和$j$($i$到$j$要有边),则答案为$max(ed_{i}+st_{j}+1)-2$(分别表示从$i$到$S$和从$j$到$T$的最长路,可以预处理)

    暴力枚举复杂度仍然不行,考虑删除$k-1$和删除$k$的变化,可以看作以下3步:

    1.$j$的枚举范围由$[k,n]$缩小为$[k+1,n]$,将$st_{k}$向之前的贡献删去

    2.查询$k$上的答案,用一个set去维护

    3.$i$的枚举范围由$[1,k-1]$扩大为$[1,k]$,将$ed_{k}$向之后的贡献加入

    用一个set维护插入、删除和查询最大值(注意要可重,因此删除要删指针),由于每一条边最多在左端点插入一次、右端点删除一次,总复杂度为$o(mlog_{2}m)$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 500005
     4 multiset<int>s;
     5 queue<int>q;
     6 vector<int>v[N],vi[N];
     7 int n,m,x,y,r[N],id[N],st[N],ed[N],ans[N];
     8 void add(int x,int y){
     9     r[y]++;
    10     v[x].push_back(y);
    11     vi[y].push_back(x);
    12 }
    13 void del(int k){
    14     assert(s.find(k)!=s.end());
    15     s.erase(s.find(k));
    16 }
    17 int main(){
    18     scanf("%d%d",&n,&m);
    19     for(int i=1;i<=m;i++){
    20         scanf("%d%d",&x,&y);
    21         add(x,y);
    22     }
    23     for(int i=1;i<=n;i++){
    24         add(0,i);
    25         add(i,n+1);
    26     }
    27     x=0;
    28     q.push(0);
    29     while (!q.empty()){
    30         int k=q.front();
    31         if ((1<=k)&&(k<=n))id[++x]=k;
    32         q.pop();
    33         for(int i=0;i<v[k].size();i++)
    34             if (--r[v[k][i]]==0)q.push(v[k][i]);
    35     }
    36     for(int i=1;i<=n;i++)
    37         for(int j=0;j<vi[id[i]].size();j++)ed[id[i]]=max(ed[id[i]],ed[vi[id[i]][j]]+1);
    38     for(int i=n;i;i--)
    39         for(int j=0;j<v[id[i]].size();j++)st[id[i]]=max(st[id[i]],st[v[id[i]][j]]+1);
    40     for(int i=1;i<=n;i++)s.insert(st[i]-1);
    41     for(int i=1;i<=n;i++){
    42         for(int j=0;j<vi[id[i]].size();j++)del(ed[vi[id[i]][j]]+st[id[i]]-1);
    43         if (!s.size())ans[i]=0;
    44         else ans[i]=(*--s.end());
    45         for(int j=0;j<v[id[i]].size();j++)s.insert(ed[id[i]]+st[v[id[i]][j]]-1);
    46     }
    47     ans[0]=ans[1];
    48     for(int i=2;i<=n;i++)ans[0]=min(ans[0],ans[i]);
    49     for(int i=1;i<=n;i++)
    50         if (ans[i]==ans[0]){
    51             printf("%d %d",id[i],ans[i]);
    52             return 0;
    53         }
    54 }
    View Code
  • 相关阅读:
    处理图片
    打死都不放手
    美白
    词云
    太阳花绘制
    测评软件Lemon教程
    --解释?说明:--
    T1 数字配对 题解
    P1100 高低位交换
    P1143 进制转换
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14051810.html
Copyright © 2011-2022 走看看