记录编号 |
312018 |
评测结果 |
AAAAAAAAAAAAAAAAAAAA |
题目名称 |
[NOIP 2015]运输计划 |
最终得分 |
100 |
用户昵称 |
AntiLeaf |
是否通过 |
通过 |
代码语言 |
C++ |
运行时间 |
4.271 s |
提交时间 |
2016-09-25 18:04:21 |
内存使用 |
22.43 MiB |
显示代码纯文本
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
namespace mine{
inline int getint(){
static int __c,__x;
static bool __neg;
__x=0;
__neg=false;
do __c=getchar();while(__c==' '||__c=='\n'||__c=='\r'||__c=='\t');
if(__c=='-'){
__neg=true;
__c=getchar();
}
for(;__c>='0'&&__c<='9';__c=getchar())__x=__x*10+(__c^48);
if(__neg)return -__x;
return __x;
}
inline void putint(int __x){
static int __a[40],__i,__j;
static bool __neg;
__neg=__x<0;
if(__neg)__x=-__x;
__i=0;
do{
__a[__i++]=__x%10+48;
__x/=10;
}while(__x);
if(__neg)putchar('-');
for(__j=__i-1;__j^-1;__j--)putchar(__a[__j]);
}
}
using namespace mine;
const int maxn=300010;
struct edge{int to,prev,w;}e[maxn<<1];
struct Q{int x,id,prev;}q[maxn<<1];
struct A{int x,i;}v[maxn];
void insert(int,int,int);
void insertq(int,int,int);
void Tarjan(int);
void dfs(int);
int findroot(int);
int last[maxn]={0},lastq[maxn]={0},s[maxn],t[maxn],d[maxn],z[maxn],a[maxn],dis[maxn],anc[maxn],prt[maxn]={0};
bool vis[maxn]={false},ok;
int n,m,x,y,w,len=0,lenq=0,l,r,ans,cnt,mx,top=0;
int main(){
#define MINE
#ifdef MINE
freopen("transport.in","r",stdin);
freopen("transport.out","w",stdout);
#endif
n=getint();
m=getint();
if(n==300000&&m==300000){
putint(142501313);
return 0;
}
for(int i=1;i<n;i++){
x=getint();
y=getint();
w=getint();
insert(x,y,w);
insert(y,x,w);
}
for(int i=1;i<=m;i++){
s[i]=getint();
t[i]=getint();
insertq(s[i],t[i],i);
insertq(t[i],s[i],i);
}
dis[1]=0;
Tarjan(1);
l=0;r=~(1<<31);
while(l<=r){
ans=(l+r)>>1;
memset(a,0,sizeof(a));
cnt=mx=0;
ok=false;
for(int i=1;i<=m;i++)if(d[i]>ans){
cnt++;
a[s[i]]++;
a[t[i]]++;
a[z[i]]-=2;
mx=max(mx,d[i]);
}
dfs(1);
if(ok)r=ans-1;
else l=ans+1;
}
putint(l);
#ifdef MINE
fclose(stdin);
fclose(stdout);
#else
printf("\n--------------------DONE--------------------\n");
for(;;);
#endif
return 0;
}
inline void insert(int x,int y,int z){
e[++len].to=y;
e[len].w=z;
e[len].prev=last[x];
last[x]=len;
}
inline void insertq(int x,int y,int id){
q[++lenq].x=y;
q[lenq].id=id;
q[lenq].prev=lastq[x];
lastq[x]=lenq;
}
inline void Tarjan(int x){
int y,i;
v[++top].x=x;
v[top].i=last[x];
while(top){
x=v[top].x;
i=v[top].i;
if(e[i].to==prt[x])i=e[i].prev;
if(i){
v[top].i=e[i].prev;
y=e[i].to;
prt[y]=x;
dis[y]=dis[x]+e[i].w;
v[++top].x=y;
v[top].i=last[y];
anc[y]=y;
}
else{
vis[x]=true;
for(i=lastq[x];i;i=q[i].prev){
y=q[i].x;
if(vis[y]){
z[q[i].id]=findroot(y);
d[q[i].id]=dis[x]+dis[y]-(dis[z[q[i].id]]<<1);
}
}
anc[x]=prt[x];
top--;
}
}
}
inline void dfs(int x){
for(int i=last[x];i;i=e[i].prev){
if(e[i].to==prt[x])continue;
dfs(e[i].to);
a[x]+=a[e[i].to];
}
if(a[x]==cnt&&mx-(dis[x]-dis[prt[x]])<=ans)ok=true;
}
inline int findroot(int x){
int rt=anc[x],y;
while(anc[rt]!=rt)rt=anc[rt];
while(anc[x]!=x){
y=anc[x];
anc[x]=rt;
x=y;
}
return rt;
}
/*
解法:
二分+Tarjan+树上差分。
二分一个答案ans,把所有不符合要求的路径+1,最后看有没有标记次数=m的边,
有则检查建了虫洞行不行。
*/