【BZOJ1999】【NOIP2007】树网的核 单调队列优化DP

来源:互联网 发布:js监听扫描枪 编辑:程序博客网 时间:2024/05/20 20:03

题目描述

  题目很长,大家自己去看吧。

  bzoj

  vijos

  原题n300

  加强版n500000

题解

  这种东西当然要猜结论的啦,否则会比较麻烦。

结论1:如果有很多条直径,那么不管核在哪条直径上,最小偏心距都相同。

结论2 :任意一条路径的偏心距不会小于核的最小偏心距。

  这两个结论的证明方法类似。都是考虑两条路径的公共部分和非公共部分。如果最远的点到路径上的最近的点都在公共部分上,则偏心距相同。任意两条直径的非公共部分长度相同,最远的点到直径上的最近的点的距离显然大于最远的点到其他路径上的最近的点的距离(否则这条直径就不是直径了)。

  结论1告诉我们可以只考虑一条路径,结论2告诉我们可以考虑所有O(n2)条路径而不用管这条路径是否在直径上。

  对于n300,直接暴力枚举路径的两个端点,枚举任意一个点,算出所有其他点到这条路径的距离,就是(这个点到一个端点的距离+这个点到另一个端点的距离这条路径的长度)÷2,算出最大值然后更新答案。

  算最短路用floyd

  时间复杂度:O(n3)

  对于n500000,找出其中一条直径,把这条直径拿出来,算出每个点往右距离不超过s的点是哪个,算出每个点忽略直径上左边所有点/右边所有点/左边+右边所有点的最远距离。这三部分的最大值就是一条路径的答案。然后从右往左计算答案,用单调队列维护答案:如果新加入队列的偏心距比队尾的偏心距大,可以把队尾删掉。算出所有路径的答案然后取min就可以了。

  时间复杂度:O(n)

代码

//O(n^3)#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>#include<cmath>#include<functional>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> pii;typedef pair<ll,ll> pll;void sort(int &a,int &b){    if(a>b)        swap(a,b);}void open(const char *s){#ifndef ONLINE_JUDGE    char str[100];    sprintf(str,"%s.in",s);    freopen(str,"r",stdin);    sprintf(str,"%s.out",s);    freopen(str,"w",stdout);#endif}int rd(){    int s=0,c;    while((c=getchar())<'0'||c>'9');    do    {        s=s*10+c-'0';    }    while((c=getchar())>='0'&&c<='9');    return s;}int upmin(int &a,int b){    if(b<a)    {        a=b;        return 1;    }    return 0;}int upmax(int &a,int b){    if(b>a)    {        a=b;        return 1;    }    return 0;}int f[310][310];int main(){    int n,s;    scanf("%d%d",&n,&s);    memset(f,0x3f,sizeof f);    int i,x,y,z;    for(i=1;i<n;i++)    {        scanf("%d%d%d",&x,&y,&z);        f[x][y]=f[y][x]=z;    }    for(i=1;i<=n;i++)        f[i][i]=0;    int j,k;    for(k=1;k<=n;k++)        for(i=1;i<=n;i++)            if(i!=k)                for(j=1;j<=n;j++)                    if(j!=i&&j!=k)                        f[i][j]=min(f[i][j],f[i][k]+f[k][j]);    int ans=0x7fffffff;    for(i=1;i<=n;i++)        for(j=1;j<=n;j++)            if(f[i][j]<=s)            {                int now=0;                for(k=1;k<=n;k++)                    now=max(now,(f[k][i]+f[k][j]-f[i][j])/2);                ans=min(ans,now);            }    printf("%d\n",ans);    return 0;}
//O(n)#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>#include<cmath>#include<functional>#include<queue>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> pii;typedef pair<ll,ll> pll;void sort(int &a,int &b){    if(a>b)        swap(a,b);}void open(const char *s){#ifndef ONLINE_JUDGE    char str[100];    sprintf(str,"%s.in",s);    freopen(str,"r",stdin);    sprintf(str,"%s.out",s);    freopen(str,"w",stdout);#endif}int rd(){    int s=0,c;    while((c=getchar())<'0'||c>'9');    do    {        s=s*10+c-'0';    }    while((c=getchar())>='0'&&c<='9');    return s;}int upmin(int &a,int b){    if(b<a)    {        a=b;        return 1;    }    return 0;}int upmax(int &a,int b){    if(b>a)    {        a=b;        return 1;    }    return 0;}struct graph{    int v[1000010];    int w[1000010];    int t[1000010];    int h[500010];    int n;    graph()    {        memset(h,0,sizeof h);        n=0;    }    void add(int x,int y,int z)    {        n++;        v[n]=y;        w[n]=z;        t[n]=h[x];        h[x]=n;    }};graph g;int from[500010];int b[500010];queue<int> q;int d[500010];int w[500010];void bfs(int x){    memset(d,-1,sizeof d);    d[x]=0;    q.push(x);    int i;    from[x]=0;    w[x]=0;    while(!q.empty())    {        x=q.front();        q.pop();        for(i=g.h[x];i;i=g.t[i])            if(d[g.v[i]]==-1)            {                d[g.v[i]]=d[x]+g.w[i];                w[g.v[i]]=g.w[i];                from[g.v[i]]=x;                q.push(g.v[i]);            }    }}void dfs(int x,int fa,int dep,int &s){    s=max(s,dep);    int i;    for(i=g.h[x];i;i=g.t[i])        if(!b[g.v[i]]&&g.v[i]!=fa)            dfs(g.v[i],x,dep+g.w[i],s);}int a[500010];int c[500010];int f[500010];int fl[500010];int fr[500010];pii q2[500010];int head,tail;void add(int x){    while(tail>=head&&q2[tail].second<=f[x])        tail--;    q2[++tail]=pii(x,f[x]);}void del(int x){    if(q2[head].first==x)        head++;}int main(){    freopen("bzoj1999.in","r",stdin);    freopen("bzoj1999.out","w",stdout);    int n,m;    scanf("%d%d",&n,&m);    int i,x,y,z;    for(i=1;i<n;i++)    {        scanf("%d%d%d",&x,&y,&z);        g.add(x,y,z);        g.add(y,x,z);    }    bfs(1);    x=1;    for(i=1;i<=n;i++)        if(d[i]>d[x])            x=i;    bfs(x);    for(i=1;i<=n;i++)        if(d[i]>d[x])            x=i;    int t=0;    do    {        a[++t]=x;        c[t]=w[x];        x=from[x];    }    while(x);    for(i=1;i<=t;i++)        b[a[i]]=1;    int j;    for(i=1;i<=t;i++)        for(j=g.h[a[i]];j;j=g.t[j])            if(!b[g.v[j]])                dfs(g.v[j],0,g.w[j],f[i]);    for(i=1;i<=t;i++)        fl[i]=max(f[i],fl[i-1]+c[i-1]);    for(i=t;i>=1;i--)        fr[i]=max(f[i],fr[i+1]+c[i]);    for(i=1;i<=t;i++)        c[i]+=c[i-1];    head=1;    tail=0;    j=1;    int ans=0x7fffffff;    for(i=1;i<=t;i++)    {        add(i);        while(c[i-1]-c[j-1]>m)        {            del(j);            j++;        }        ans=min(ans,max(max(fl[j],fr[i]),q2[head].second));    }    printf("%d\n",ans);    return 0;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 网店加盟被骗怎么办 分期乐忘记账号怎么办 贴墙纸遇到插头怎么办 用了屈臣氏过敏怎么办 商品房内电箱不符合标准怎么办 淘宝上恶意退货怎么办 退货率高了怎么办 淘宝店被关了钱怎么办 买家不申请退款怎么办 被买家恶意投诉怎么办 淘宝投诉后退款怎么办 天猫投诉不成功怎么办 苹果手机打不开流量怎么办 苹果6流量打不开怎么办 苹果笔记本电脑打不开软件怎么办 苹果软件蜂窝打不开怎么办 苹果手机wifi打不开怎么办 苹果app变成韩语怎么办 ipad键盘变成英文怎么办 苹果8商店打不开怎么办 苹果手机不能下载怎么办 天猫魔盒遥控器丢了怎么办 电视盒子声音小怎么办 宽带los亮红灯怎么办 猫的lan灯不亮怎么办 光猫los灯不亮怎么办 移动宽带红灯亮怎么办 ie打不开网页怎么办win10 win10系统ie打不开怎么办 笔记本电脑玩lol卡怎么办 火狐浏览器电脑版打不开怎么办 手机淘宝没密码怎么办 实体店不让退货怎么办 出生公证双认证怎么办 手机淘宝网速慢怎么办 淘宝开店认证不通过怎么办 开网店不会做图怎么办 库乐队上传错误怎么办 淘宝定金不退怎么办 淘宝店激活认证怎么办 淘宝店铺不卖怎么办