51nod 1307

来源:互联网 发布:郭德纲网络剧 编辑:程序博客网 时间:2024/06/01 14:26

题意:给出一棵树,每条边上都有一个权值,每个点也有一个权值,当一条边的子树所有节点权值和超过这条边的权值时,这条边会断开。边按序给出,问最多能有几条边。
每条边的可承受重量可以看成其下端点的可承受重量。
数据比较弱,首先可以按题意模拟,当加入一个新点时,向上不断查找父节点,查看新点到根节点的这条路径是否有边会超限断开。

#include<cstdio>#include<cstring>#include<iostream>#define LL long longusing namespace std;const int maxn=5e4+50;const int maxe=5e4+50;const LL Inf=1e18;int r[maxn], w[maxn], p[maxn];int n;int main(){    int par;    int ans=-1;    scanf("%d", &n);    for(int i=1;i<=n;i++){        scanf("%d%d%d", &r[i], &w[i], &p[i]);        p[i]++;        if(ans>=0) continue;        int v=i, tw=w[i];        while(v){            r[v]-=tw;            if(r[v]<0) ans=i-1;            v=p[v];        }    }    if(ans==-1) ans=n;    printf("%d\n", ans);    return 0;}

但上面那种方法的复杂度是O(n^2)的,在整棵树退化成一条链的时候,n=50000时耗时6s+。
最大值问题,考虑二分,每次二分出来的值可以通过一次深搜来验证。

#include<cstdio>#include<cstring>#include<iostream>#define LL long longusing namespace std;const int maxn=5e4+50;const int maxe=5e4+50;const LL Inf=1e18;struct Edge{    int from, to, next;};Edge edges[maxe];int head[maxn], ecnt;int n;LL r[maxn], w1[maxn], w2[maxn];bool flag;void add_edge(int u,int v){    edges[ecnt]=Edge{u, v, head[u]};    head[u]=ecnt++;}void dfs(int u,int lim){    if(!flag) return;    LL &tmp=w2[u];    tmp=w1[u];    for(int i=head[u];i!=-1;i=edges[i].next)    if(i<=lim){        int v=edges[i].to;        dfs(v, lim); if(!flag) return;        tmp+=w2[v];    }    if(tmp>r[u]) flag=false;}void init(){    int par;    memset(head, -1, sizeof head);    ecnt=1;    scanf("%d", &n);    for(int i=1;i<=n;i++){        scanf("%lld%lld%d", &r[i], &w1[i], &par);        par++;        add_edge(par, i);    }    w1[0]=0;    r[0]=Inf;}void solve(){    int l=1, r=n;    int ans=0;    while(l<=r){        int mid=(l+r)>>1;        flag=true;        dfs(0, mid);        if(flag){            ans=mid;            l=mid+1;        }else{            r=mid-1;        }    }    printf("%d\n", ans);}int main(){    init();    solve();    return 0;}

但上面的代码在树深度过深时,比如n=50000且退化成一条链时,会爆栈。把递归深搜改成循环,把使用系统栈改成使用STL的栈。

#pragma comment (linker,"/stack:102400000,102400000")#include<stack>#include<queue>#include<cstdio>#include<cstring>#include<iostream>#define LL long longusing namespace std;const int maxn=5e4+50;const int maxe=5e4+50;const LL Inf=1e18;struct Edge{    int from, to, next;};Edge edges[maxe];int head[maxn], ecnt;int n;LL r[maxn], w1[maxn], w2[maxn];bool flag;stack<int> S;queue<int> Q;void add_edge(int u,int v){    edges[ecnt]=Edge{u, v, head[u]};    head[u]=ecnt++;}void dfs(int x,int lim){    Q.push(x);    while(!Q.empty()){        int u=Q.front();        Q.pop();        S.push(u);        for(int i=head[u];i!=-1;i=edges[i].next)        if(i<=lim){            int v=edges[i].to;            Q.push(v);        }    }    while(!S.empty()){        int u=S.top(); S.pop();        LL &tmp=w2[u];        tmp=w1[u];        for(int i=head[u];i!=-1;i=edges[i].next)        if(i<=lim){            int v=edges[i].to;            tmp+=w2[v];            if(tmp>r[u]) flag=false;            if(!flag) return;        }    }}void init(){    int par;    memset(head, -1, sizeof head);    ecnt=1;    scanf("%d", &n);    for(int i=1;i<=n;i++){        scanf("%lld%lld%d", &r[i], &w1[i], &par);        par++;        add_edge(par, i);    }    w1[0]=0;    r[0]=Inf;}void solve(){    //puts("Infinity is awesome!");    int l=1, r=n;    int ans=0;    while(l<=r){        int mid=(l+r)>>1;        flag=true;        dfs(0, mid);        if(flag){            ans=mid;            l=mid+1;        }else{            r=mid-1;        }    }    printf("%d\n", ans);}int main(){    //freopen("data.txt", "r", stdin);    init();    solve();    return 0;}
原创粉丝点击