zoukankan      html  css  js  c++  java
  • BZOJ1791 [Ioi2008]Island 岛屿[基环树+单调队列优化DP]

    基环树直径裸题。

    首先基环树直径只可能有两种形式:每棵基环树中的环上挂着的树的直径,或者是挂在环上的两个树的最大深度根之间的距离之和。

    所以,先对每个连通块跑一遍,把环上的点找出来,然后对环上每个点跑一遍树的直径(这里采用DP形式,可以顺便求出最大深度,注意DP树的直径方法。。就是考虑跨过每个点的链。。见lyd书树的直径一章)。

    然后就变成了环上每个点有权值,求最大价值。`````

    基环树上的环处理起来方法比较多,这里由于是DP,采用断环成链的方法,把环复制两遍,然后对第二份进行DP,就可以转化为1D1DDP,然后显然就可以单调队列优化了。

    bzoj栈没开大,所以要手写递归栈或者用其他方法。。不想写了,所以直接在luogu交了。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define mst(x) memset(x,0,sizeof x)
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=1e6+7;
    24 struct thxorz{
    25     int head[N],nxt[N<<1],to[N<<1],w[N<<1],tot;
    26     thxorz(){tot=1;}
    27     inline void add(int x,int y,int z){
    28         to[++tot]=y,nxt[tot]=head[x],head[x]=tot,w[tot]=z;
    29         to[++tot]=x,nxt[tot]=head[y],head[y]=tot,w[tot]=z;
    30     }
    31 }G;
    32 int n,m;
    33 #define y G.to[j]
    34 int vis[N],lp[N<<1],q[N],l,r,lpfa,cir,flag;
    35 ll d[N],sum[N<<1],ans,res;
    36 void dfs(int x,int fa){//dbg(x);
    37     vis[x]=1;
    38     for(register int j=G.head[x];j&&!flag;j=G.nxt[j])if(j^(fa^1)){//dbg(y);
    39         if(!vis[y]){
    40             dfs(y,j);
    41             if(flag)lp[++m]=x,sum[m]=sum[m-1]+G.w[j];
    42         }
    43         else return lpfa=y,lp[m=1]=x,sum[1]=G.w[j],flag=1,void();
    44     }
    45     if(!flag)vis[x]=0;
    46     if(x==lpfa)flag=0;
    47 }
    48 void dp(int x){//dbg(x);
    49     vis[x]=1;
    50     for(register int j=G.head[x];j;j=G.nxt[j])if(!vis[y])
    51         dp(y),MAX(ans,d[y]+d[x]+G.w[j]),MAX(d[x],d[y]+G.w[j]);
    52 }
    53 #undef y
    54 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    55     read(n);
    56     for(register int i=1,y,z;i<=n;++i)read(y),read(z),G.add(i,y,z);
    57     for(register int i=1;i<=n;++i)if(!vis[i]){
    58         l=1,r=ans=m=0;dfs(i,0);//dbg2("ok loop",m);
    59         for(register int j=1;j<=m;++j)dp(lp[j]);//dbg2("ok tree",lp[j]);
    60         for(register int j=1;j<=m;++j){
    61             while(l<=r&&d[lp[j]]-sum[j]>=d[lp[q[r]]]-sum[q[r]])--r;
    62             q[++r]=j;
    63         }
    64         for(register int j=m+1;j<=m<<1;++j){
    65             while(l<=r&&q[l]<=j-m)++l;
    66             sum[j]=sum[m]+sum[j-m],lp[j]=lp[j-m];
    67             MAX(ans,d[lp[q[l]]]+d[lp[j]]+sum[j]-sum[q[l]]);
    68             while(l<=r&&d[lp[q[r]]]-sum[q[r]]<=d[lp[j]]-sum[j])--r;
    69             q[++r]=j;
    70         }
    71         res+=ans;
    72     }
    73     printf("%lld
    ",res);
    74     return 0;
    75 }
    View Code

    总结:环上问题多有断环成链做法。

  • 相关阅读:
    android中的style部分属性值介绍
    eclipse 代码提示快捷键 alt+/
    ListView中Spinner的使用+ ListView中常用样式和属性
    通过重载new和delete实现简单的对象池
    C# 3.0下有限状态机的一种优雅的实现
    更改MenuStrips样式
    WinPcap编程3——获取网络适配器列表
    lex and yacc
    WinPcap编程4——捕获数据包
    WinPcap编程2——环境搭建
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11807193.html
Copyright © 2011-2022 走看看