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\n",res); 74 return 0; 75 }
总结:环上问题多有断环成链做法。