【NOIP2016提高A组集训第10场11.8】时空传送
2016-11-08 22:46
330 查看
Description
经过旷久的战争,ZMiG和707逐渐培养出了深厚的感♂情。他们逃到了另一块大陆上,决定远离世间的纷争,幸福地生活在一起。钟情707的neither_nor决心要把他们拆散,他要动用手中最大杀器之一——超时空传送仪来分开ZMiG和707。ZMiG和707所在的大陆可以被描述成N个点M条边的有向无环图。707和ZMiG自带魔法防御,neither_nor只可以用超时空传送仪把707传送到一个点,再把ZMiG传送到一个能到达707所在点的点,然后为ZMiG指定一条寻找707的路径,他当然想把707和ZMiG分隔的越远越好,所以他会规划一条距离最长的路线。707自然也知道这一点,但是她没有办法阻止,她唯一能做且必须做的就是利用手中的炸药炸掉大陆上的一个点,然后与这条大陆相连的边也会自动被抹去,这样就会打乱neither_nor本来的计划。但是由于707过于敏捷,他的行动必须在neither_nor之前。换句话说,707需要先选择他炸掉哪个点,之后neither_nor一定会选择一条图中存在的最长路径来分开ZMiG和707。707想让这条路径最短,所以她要问问你他应该炸掉哪个点。
Solution
这道题,很难,比赛的时候就是一脸懵逼的去打暴搜40分。比赛之后,用了好久才弄懂,觉得这个想法十分的机智。
设f[i]和g[i]分别为从一个点走到i的最长路和i到另一个点的最长路(就是从S到i的最长路和i到T的最长路)
首先,在原图中,一条边的贡献就是f[a]+g+1,a和b是起点和终点。
考虑,删掉了一条边,怎样操作才不会去影响别的边的情况。
因为是有向无环图,所以我们可以考虑一下拓扑排序。
然后我们试着按拓扑序一个个的去删点,那么一开始所有点的情况(最长路)都是g[i]。
那么我们在考虑用一个堆去维护一下最长路。
那么我们现在把x删掉之前,因为已经从上面的点走下来了,那么前面的点的信息就没有用了,所以把连向x的点的信息(f[y]+g[x]+1)从堆中踢掉,然后他自己的信息(g[x])也没有用了,因为我们马上要把x踢掉了,所以把这个也从堆中踢掉。
然后,我们去一下堆首更新一下答案。
因为x没了,即将有一些新的点的信息要更新,所以把x连出去的点的信息(f[x]+g[y]+1)放进堆里面。因为虽然x断了,但是f[x]还是有用的,所以把x再放进堆里面。
c++用multiset比较好实现。
[b]Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<set> #define fo(i,a,b) for(i=a;i<=b;i++) #define fod(i,a,b) for(i=a;i>=b;i--) #define rep(i,a) for(i=first[a];i;i=next[i]) #define rep1(i,a) for(i=first1[a];i;i=next1[i]) using namespace std; const int maxn=75007; int i,j,k,l,n,m,ans; int first[maxn*2],last[maxn*2],next[maxn*2],chang[maxn*2],num; int first1[maxn*2],last1[maxn*2],next1[maxn*2],chang1[maxn*2],num1; int f[maxn*2],g[maxn*2],data[maxn*10],S,T,p[maxn*2],x,ans1,c[maxn*2]; bool bz[maxn*2]; multiset<int>t; void add(int x,int y,int z){last[++num]=y,next[num]=first[x],first[x]=num,chang[num]=z;} void add1(int x,int y,int z){last1[++num1]=y,next1[num1]=first1[x],first1[x]=num1,chang1[num1]=z;} void tuopu(){ int i,head=0,tail=p[0],now; while(head<tail){ now=p[++head]; rep(i,now){ if(c[last[i]]){ c[last[i]]--; if(!c[last[i]])p[++tail]=last[i]; } } } p[0]=tail; } int main(){ // freopen("fan.in","r",stdin); freopen("chronosphere.in","r",stdin); freopen("chronosphere.out","w",stdout); scanf("%d%d",&n,&m);S=0,T=n+1; fo(i,1,m)scanf("%d%d",&k,&l),add(k,l,1),add1(l,k,1),c[l]++; fo(i,1,n)if(!c[i])p[++p[0]]=i,c[i]=0; tuopu(); fo(i,1,n){ rep(j,p[i]){ f[last[j]]=max(f[p[i]]+1,f[last[j]]); } } fod(i,n,1){ rep1(j,p[i]){ g[last1[j]]=max(g[p[i]]+1,g[last1[j]]); } } fo(i,1,n)t.insert(g[i]); ans=0x7fffffff; fo(j,1,n){ x=p[j]; rep1(i,x){ if(!last1[i])continue; t.erase(t.find(f[last1[i]]+g[x]+1)); } t.erase(t.find(g[x])); k=*--t.end(); if(k<ans||k==ans&&x<ans1)ans=k,ans1=x; rep(i,x){ if(last[i]==n+1)continue; t.insert(g[last[i]]+f[x]+1); } t.insert(f[x]); } printf("%d %d\n",ans1,ans); }
相关文章推荐
- JZOJ4876. 【NOIP2016提高A组集训第10场11.8】时空传送 拓扑序判断最长路是否合法
- 【NOIP2016提高A组集训第10场11.8】时空传送
- JZOJ4878. 【NOIP2016提高A组集训第10场11.8】时空传送
- 【JZOJ4878】【NOIP2016提高A组集训第10场11.8】时空传送
- 【JZOJ4876】【NOIP2016提高A组集训第10场11.8】基因突变
- 【JZOJ4877】【NOIP2016提高A组集训第10场11.8】力场护盾
- 【NOIP2016提高A组集训第10场11.8】力场护盾
- JZOJ4877. 【NOIP2016提高A组集训第10场11.8】力场护盾
- JZOJ4876. 【NOIP2016提高A组集训第10场11.8】基因突变(2017.8B组)
- NOIP提高A组集训第10场11.8 力场护盾
- JZOJ 4879. 【NOIP2016提高A组集训第11场11.9】少女觉
- 【NOIP2016提高A组集训第14场11.12】最近公共祖先
- 【JZOJ4894】【NOIP2016提高A组集训第16场11.15】SJR的直线
- 【JZOJ4895】【NOIP2016提高A组集训第16场11.15】三部曲
- 小W学物理【NOIP2016提高A组集训第1场10.29】
- 【JZOJ4841】【NOIP2016提高A组集训第4场11.1】平衡的子集
- JZOJ4854【NOIP2016提高A组集训第6场11.3】小澳的坐标系
- JZOJ4866【NOIP2016提高A组集训第8场11.5】禅与园林艺术
- 【NOIP2016提高A组集训第5场11.2】行走
- 【JZOJ4888】【NOIP2016提高A组集训第14场11.12】最近公共祖先