NOIP系列

Posted on 2017-10-16 10:42  Amphetamine  阅读(199)  评论(2编辑  收藏  举报

NOIP2015运输计划

 

真是

这题

卡死我了

tarjan离线lca复杂度O(n)

最后各种卡常,多交几遍才A(洛谷104ms)

%%%zk学长609ms

注意二分的时候左边界要定成0

根据题意,显然先想到二分,然后求交集,在集合里找有没有边删掉之后使得所有路长度<mid

#include<bits/stdc++.h>
using namespace std;
char *TT,*mo,but[(1<<15)+2];
#define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin)),TT==mo)?0:*TT++)
inline int read(){
    int x=0,c=0,f=1;
    for(;c<'0'||c>'9';c=getchar())f=c!='-';
    for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
    return f?x:-x;
}
int root;
struct Q{
    int a,b,lca,len;
}q[300010];
int head1[300010];
bool comp(Q A,Q B){
    return A.len>B.len;
}
struct T1{
    int next,to,num;
}e1[600010];
int cnt1;
void add1(int u,int v,int c){
    e1[++cnt1].to=v;e1[cnt1].next=head1[u];e1[cnt1].num=c;head1[u]=cnt1;
}
struct T{
    int next,to,cal;
}e[600010];
int cnt;
int head[300010];
int deep[300010];
int p[300010];
void add(int u,int v,int c){
    e[++cnt].to=v;e[cnt].next=head[u];e[cnt].cal=c;head[u]=cnt;
}
int sum[300010];
int n,m;
int fa[300010];
int find(int x){
    return !(fa[x]^x)?x:fa[x]=find(fa[x]);
}
void un(int x,int y){
    x=find(x),y=find(y);
    if(x^y)fa[x]=y;
}
bitset<300010>vis;
void init(int u){
    vis[u]=1;
    for(int i=head[u];i;i=e[i].next){
        if(vis[e[i].to])continue;
        deep[e[i].to]=deep[u]+e[i].cal;
        p[e[i].to]=e[i].cal;
        init(e[i].to);
        un(e[i].to,u);
    }
    for(int i=head1[u];i;i=e1[i].next){
        int v=e1[i].to;
        int ms=e1[i].num;
        if(vis[v]!=0){
            q[ms].lca=find(v);
        }
    } 
}
void dfs(int faf,int u){
    for(int i=head[u];i;i=e[i].next){
        if(!(e[i].to^faf))continue;
        dfs(u,e[i].to);
        sum[u]+=sum[e[i].to];
    }
}
bool check(int mid){
    memset(sum,0,sizeof(sum));
    int ret=0;
    register int i,j;
    for(i=1;i<=m;i++){
        if(q[i].len<=mid)break;
        sum[q[i].a]++;
        sum[q[i].b]++;
        sum[q[i].lca]-=2;
        ret=max(ret,q[i].len-mid);
    }
    i--;
    dfs(0,root);
    for(j=1;j<=n;j++){
        if(p[j]>=ret&&sum[j]==i)return 1;
    }
    return 0;
}
int main(){
    srand(time(NULL));
    n=read(),m=read();
    for(int i=1;i<=n;i++)fa[i]=i;
    int x,y,z;
    for(int i=1;i<n;i++){
        x=read(),y=read(),z=read();
        add(x,y,z);
        add(y,x,z);
    }
    root=rand()%n+1;
    deep[root]=0;
    for(int i=1;i<=m;i++){
        q[i].a=read(),q[i].b=read();
        add1(q[i].a,q[i].b,i);
        add1(q[i].b,q[i].a,i);
    }
    init(root);
    for(int i=1;i<=m;i++){
        q[i].len=deep[q[i].a]+deep[q[i].b]-2*deep[q[i].lca];
    }
    sort(q+1,q+m+1,comp);
    int l=0,r=300000000;
    while(r>l){
        int mid=l+r>>1;
        //cout<<mid<<endl;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    cout<<l;
    return 0;
} 
View Code