zoukankan      html  css  js  c++  java
  • 【洛谷3573】[POI2014] RAJ-Rally(拓扑+堆)

    点此看题面

    • 一张(n)个点的(DAG),你可以删去一个点,要求最小化剩余图中的最长路径。
    • (nle5 imes10^5,mle10^6)

    过去点集与未来点集

    一个非常奇妙的做法。

    首先我们跑一遍拓扑,预处理出到每个点为止的最长路(d1_x)从每个点开始的最长路(d2_x),这只要简单地(DAG)(DP)一下就结束了。

    然后按照拓扑序,考虑每一个点的答案。

    有一个很神奇的思路,就是我们维护一个过去点集(A)和一个未来点集(B)(也就是操作过的点集和尚未操作的点集),那么最长路径只有三种可能:

    • (A)内部:(max_{xin A}d1_x)
    • (B)内部:(max_{xin B}d2_x)
    • (A,B)之间:(max_{uin A,vin B,(u,v)in E}d1_u+1+d2_v)

    直接拿一个堆((multiset))维护。

    然后现在我们要考虑一个点(k)的答案,由于是按拓扑序枚举的,它的前驱节点肯定都已经去了(A)中,它的后继节点肯定都还留在(B)中。

    所以要删除它的贡献,对于在(B)内部的贡献只要删除(d2_k),对于(A,B)之间的贡献也只要删去所有由它产生的贡献(可以在计算贡献的时候就记录下来)。

    那么此时的答案就是删除(k)时的答案了,与原有答案比较更新。

    接下来我们要把(k)加入过去点集,对于在(A)内部的贡献只要加入(d1_k),对于(A,B)之间的贡献只要枚举它的所有出边计算(显然后继节点(to)都在(B)中,同时我们把这个贡献扔到(to)的桶中方便拿出(to)时贡献的删除)。

    代码:(O(mlogn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 500000
    #define M 1000000
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    using namespace std;
    int n,m,deg[N+5],ee,lnk[N+5];struct edge {int to,nxt;}e[M+5];
    vector<int> p[N+5];multiset<int> S;
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	char oc,FI[FS],*FA=FI,*FB=FI;
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }using namespace FastIO;
    int q[N+5],d1[N+5],d2[N+5];I void Topo()//拓扑排序+预处理
    {
    	RI i,j,H=1,T=0;for(i=1;i<=n;++i) !deg[i]&&(q[++T]=i);
    	W(H<=T) for(i=lnk[q[H++]];i;i=e[i].nxt) !--deg[e[i].to]&&(q[++T]=e[i].to);
    	for(i=1;i<=n;++i) for(j=lnk[q[i]];j;j=e[j].nxt) d1[e[j].to]=max(d1[e[j].to],d1[q[i]]+1);//预处理到每个点为止的最长路
    	for(i=n;i>=1;--i) for(j=lnk[q[i]];j;j=e[j].nxt) d2[q[i]]=max(d2[q[i]],d2[e[j].to]+1);//预处理从每个点出发的最长路
    }
    int main()
    {
    	RI i,j,x,y;for(read(n,m),i=1;i<=m;++i) read(x,y),add(x,y),++deg[y];Topo();
    	#define T(v) (S.insert(v))
    	#define E(v) (S.erase(S.find(v)))
    	RI t,d=1e9,nd;for(i=1;i<=n;++i) T(d2[i]);for(i=1;i<=n;++i)
    	{
    		E(d2[q[i]]);for(vector<int>::iterator it=p[q[i]].begin();it!=p[q[i]].end();++it) E(*it);//从未来点集中删除
    		(nd=S.empty()?0:*--S.end())<d&&(t=q[i],d=nd);//计算当前答案
    		T(d1[q[i]]);for(j=lnk[q[i]];j;j=e[j].nxt) p[e[j].to].emplace_back(nd=d1[q[i]]+1+d2[e[j].to]),T(nd);//加入到过去点集
    	}return printf("%d %d
    ",t,d),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    简单手风琴特效、轮播
    MVC
    文字自动下拉隐藏显示
    jQuery基础 DOM操作
    JQuery基础
    SQL 中的常用函数及使用
    数据库中的T-sql语句 条件修改 高级查询
    2017-03-09 数据库的基本东西
    C#中的冒泡排序
    C#中的数组
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3573.html
Copyright © 2011-2022 走看看