5.19[bzoj树网的核]
围观了final,SJTU还是飞了,泽民同志劲啊!
膜拜归膜拜...回来开题
bzoj1999树网的核
最近就喜欢给自己找切不动的题...QAQ
ok.....昨天在家里做了一个下午+晚上 又困&又累,虽然的确是调出了一些bug但是最sb的一句话今天才刚刚调出来...晕啊
finding my 状态ing...
联赛数据n=300,现在想想真是厚道,vijos也很厚道,一个完全通不过的程序居然还A了...
Demi Guo说过思考三部曲,想法是什么,想法怎么来的,我为什么想不到.
(证明一)核一定存在于直径上,并且存在于任何一条直径上.这个证明网上blog有很多,我贴一个我看过的.
第一步自然是找直径。我们实在是很想用Floyd来求直径,但N=300的范围在那里摆着,迫使我们要寻求更快的方法。我们注意到直径的一个性质:
对于直径中的任意一点,其距离树中其他点的最远距离不超过该点到达直径端点的距离。这是个显而易见的性质。由这个性质,我们可以导出如下引理:
对于树中的任意一点,距离其最远的点一定是树的直径的某一端点。
用同样的方法,我们很容易找到另一个端点,也就求出了直径。现在的问题是:直径可能有很多条,究竟取哪一条呢?其实任意一条都是可行的。我们做如下的说明:
首先,题目中告诉我们树的所有直径的中点必然重合,也就是告诉我们:所有的直径都是相交的。从而对于任意两条不同的直径,我们可以找到一个分叉点,我们记分叉部分的长度为L1,直径总长减去L1的长度记为L2。假设这个“核”没有经过分叉点,那么两种情况:
1、 在公共部分,其最小“偏心距”一定不大于L2;
2、 在分叉部分,其最小“偏心距”一定不小于L2。
假设这个“核”经过分叉点,那么其最小偏心距至少是L1。所以很明显,其最小“偏心距”所对应的“核”必然有一部分出现在所有直径的公共部分,而对于不完全在公共部分的“核”,其“偏心距”拥有同样的下界L1,也不会影响到最终结果。
还有一个比较形象直观的证明,传送门:http://blog.csdn.net/cyxhahaha/article/details/47345999
(证明二)核找得越长越好,这个很好理解.
在找核的时候,大家都用了单调队列,我比较弱..个人感觉rmq好理解..然后MLE...又辛辛苦苦地改成了线段树...
时间慢不多说
#include<cstdio> #include<algorithm> #define inf 1<<30 #define N 500100 using namespace std; int edgenum,n,s,head ,num ,posa,posb,next[N*2],vet[N*2],pri[N*2],u ,arr ,q[N*2]; int f[500010][1],dis[4] ,tree[N*4]; void bfs(int st,int ed,int id) { int l=1,r=1,now;q[1]=st;u[st]=1;dis[id][st]=0; while(l<=r) { now=q[l];int e=head[now]; while(e>0) { int v=vet[e]; if(u[v]==0){ r++;q[r]=v;dis[id][v]=dis[id][now]+pri[e];u[v]=1; if(id==3)if(v==ed)break; } e=next[e]; } if(id==3)if(q[r]==ed)break; l++; } for(int i=0;i<=n;i++)u[i]=0; if(id==3) { num[1]=ed;num[0]=1;arr[ed]=1; for(int i=r-1;i;i--)if(dis[2][q[i]]+dis[3][q[i]]==dis[2][st]){//跟posa距离+跟posb距离==posa-posb ++num[0];num[num[0]]=q[i];arr[q[i]]=1; } } } void add(int u,int v,int w) { edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum;pri[edgenum]=w; } void bii(int x) { //printf("dis===%d\n",x); u[x]=1;int e=head[x]; while(e>0) { int v=vet[e]; if(arr[v]==0&&u[v]==0) { bii(v); f[x][0]=max(f[x][0],f[v][0]+pri[e]); } e=next[e]; } } void update(int l,int r,int st,int ed,int p,int v) { if(l==st&&r==ed){ treeView Code [p]=v;return;} int mid=(st+ed)>>1; if(r<=mid)update(l,r,st,mid,p+p,v);else if(l>mid)update(l,r,mid+1,ed,p+p+1,v);else { update(l,mid,st,mid,p+p,v);update(mid+1,r,mid+1,ed,p+p+1,v); } if(tree[p+p]>tree[p+p+1])tree[p]=tree[p+p];else tree[p]=tree[p+p+1]; } int find(int l,int r,int st,int ed,int p) { if(l==st&&r==ed)return tree[p]; int mid=(st+ed)>>1; if(r<=mid)return find(l,r,st,mid,p+p);else if(l>mid)return find(l,r,mid+1,ed,p+p+1);else return max(find(l,mid,st,mid,p+p),find(mid+1,r,mid+1,ed,p+p+1)); } int query(int st,int ed) { int tmp=0,k=0; tmp=find(st,ed,1,num[0],1); return tmp; } int main() { freopen("1999.in","r",stdin); scanf("%d%d",&n,&s);int uu,vv,ww; for(int i=1;i<=n-1;i++) { scanf("%d%d%d",&uu,&vv,&ww);add(uu,vv,ww);add(vv,uu,ww); } bfs(1,0,1);posa=0;dis[1][0]=-1;for(int i=1;i<=n;i++)if(dis[1][i]>dis[1][posa])posa=i; bfs(posa,0,2);posb=0;dis[2][0]=-1;for(int i=1;i<=n;i++)if(dis[2][i]>dis[2][posb])posb=i; bfs(posb,posa,3); //printf("%d %d\n",posa,posb); for(int i=1;i<=num[0];i++)bii(num[i]); for(int i=1;i<=num[0];i++)update(i,i,1,num[0],1,f[num[i]][0]); int l=1,r=1;int ans=inf; //printf("dis===%d\n",f[2][0]); while(l<=num[0]) { r=max(r,l); while(r+1<=num[0]&&(dis[2][num[r+1]]-dis[2][num[l]])<=s) { r++; } ans=min(ans,max(dis[2][posb]-dis[2][num[r]],max(dis[2][num[l]],query(l,r)))); l++; } printf("%d",ans); }
- CoreException: Could not calculate build plan: Plugin org.apache.maven.plugins:maven-compiler-plugin:3.1 or one of its dependencies could not be resolved
- Cocos2dx:java.lang.UnsatisfiedLinkError:findLibrary returned null 惊魂一个月
- ajaxfileupload
- 欢迎使用CSDN-markdown编辑器
- 基础总结篇之八:创建及调用自己的ContentProvider
- LINUX 挂载硬盘开机自启动
- Linux中常用的查找文件的命令
- 作业
- IDEA中搭建Scala + Play+Slick环境
- 第五次作业
- Expected an int but was 0.01 at line 1 column 782 Gson工具使用出错的解决
- ASP.NET从MVC5升级到MVC6
- 变位词(兄弟字符串)
- C语言判断分支循环函数杂记
- App架构设计经验谈:数据层的设计
- Android口袋天气系列三-->天气数据的获取
- 双目立体视觉
- CoreData VS Realm (2016-02-23更新)
- 高精度模板1.0
- App架构设计经验谈:数据层的设计