题目实际上是求环套树森林中每个环套树的直径。

对于环套树的直径,可以先找到这个环套树上面的环。然后把环上的每一点都到达的外向树上的最远距离作为这个点的权值。

那么直径一定就是从环上的某个点开始,某个点结束的。

把环拆成链,定义dp[i]表示第i个点为结束点的最远距离,显然有dp[i]=val[j]+sum[i]-sum[j-1]+val[i].显然可以用单调队列优化这个DP。

剩下的就是这样依次统计每个环套树的直径之和。

对于环套树上找环可以借鉴最小树形图找环的技巧。

首先将边定向,保证每个点的出度为1.由于环套树的性质,这样从这颗树的任意点开始搜索,一定会回到原来访问过的点,在这个过程中记录好每个点的前驱。

就可以很easy的将这个环找出来。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#include <cctype>
#include <iostream>
#define N 1050000
using namespace std;
inline int getc() {
static const int L = <<;
static char buf[L],*S=buf,*T=buf;
if(S==T){
T=(S=buf)+fread(buf,,L,stdin);
if(S==T)return EOF;
}
return *S++;
}
inline int getint() {
int c;
while(!isdigit(c = getc()));
int tmp = c-'';
while(isdigit(c=getc()))
tmp=(tmp<<)+(tmp<<)+c-'';
return tmp;
}
struct Syndra
{
int u,v,len,next;
}e[N];
struct Fiona
{
int edge,flag1,flag2;
long long temp,max1,max2;
}s[N];
int head[N],cnt,n;
int visit[N],next[N],len[N];
int i,j,k;
long long sa[N],pre[N],ans;
void add(int u,int v,int len)
{
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].len=len;
e[cnt].next=head[u];
head[u]=cnt;
}
int que[N<<];
long long sum[N<<],ret;
long long dp(int num)
{
int top,tail;
int u,b,star;
int et;
for(et=;et<(num<<);et++)
{
sum[et]=sum[et-]+pre[(et-)>=num?(et--num):(et-)];
}
top=tail=;
/*
que[top]=0;
for(et=1;et<(num<<1);et++)
{
while(et-que[top]>=num)top++;
u=que[top];
ret=max(ret,sa[et>=num?et-num:et]+sa[u>=num?u-num:u]+sum[et]-sum[u]);
b=que[tail];
que[++tail]=et;
for(star=tail;star>top;b=que[star-1])
{
if(sum[et]-sum[b]+sa[b]<sa[et])
{
que[star]=b;
que[--star]=et;
}
else break;
}
tail=star;
}
*/
que[tail++]=;
for(et=;et<(num<<);++et)
{
while(top<tail&&et-que[top]>=num)++top;
u=que[top];
ret=max(ret,sa[et>=num?et-num:et]+sa[u>=num?u-num:u]+sum[et]-sum[u]);
while(top<tail&&sa[et>=num?et-num:et]>=sa[que[tail-]>=num?que[tail-]-num:que[tail-]]+sum[et]-sum[que[tail-]])--tail;
que[tail++]=et;
}
return ret;
}
void build()
{
cnt=;
memset(head,,sizeof(head));
memset(visit,,sizeof(visit));
n=getint();
for(i=;i<=n;i++)
{
next[i]=getint();
len[i]=getint();
add(next[i],i,len[i]);
}
}
stack<int>sk;
int fa[N];
void dfs(int x)
{
if(s[x].edge==)
{
sk.pop();
if(s[x].flag2)ret=max(ret,s[x].max1+s[x].max2);
if(visit[x]==-)
return ;
x = sk.top();
{
int v,tt=s[x].edge;
v=e[tt].v;
visit[v]=i;
s[x].temp=s[v].max1+e[tt].len;
if(s[x].max1<s[x].temp)
{
if(s[x].flag1)s[x].max2=s[x].max1,s[x].flag2=;
else s[x].flag1=;
s[x].max1=s[x].temp;
}
else if(s[x].max2<s[x].temp)s[x].max2=s[x].temp,s[x].flag2=;
s[x].edge=e[tt].next;
}
return ;
}
int v,tt=s[x].edge;
v=e[tt].v;
if(visit[v]==-)
{
s[x].edge=e[tt].next;
return ;
}
fa[v]=x;
s[v].edge=head[v];
sk.push(v);
}
long long handle(int x)
{
s[x].edge=head[x];
sk.push(x);
while(!sk.empty())
{
dfs(sk.top());
}
return s[x].max1;
}/*handle(long long)+dfs(void)=dfs(long long)*/
/*long long dfs(int x)
{
int et,v,flag1,flag2;
long long max1,max2;
for(max1=max2=0,flag1=flag2=0,et=head[x];et;et=e[et].next)
{
v=e[et].v;
if(visit[v]==-1)continue;
temp=dfs(v)+e[et].len;
visit[v]=i;
if(max1<temp)
{
if(flag1)max2=max1,flag2=1;
max1=temp;
flag1=1;
}
else if(max2<temp)max2=temp,flag2=1;
}
if(flag2)ret=max(ret,max1+max2);
return max1;
}*/
int main()
{
int u,v;
build();
for(i=;i<=n;i++)
{
if(!visit[i])
{
for(u=i;!visit[u];u=next[u])
{
visit[u]=i;
}
if(visit[u]==i)
{
ret=;cnt=;
visit[u]=-;
for(v=next[u];v!=u;v=next[v])
{
visit[v]=-;
}
v=u;
do{
pre[cnt]=len[v];
sa[cnt++]=handle(v);
v=next[v];
}while(v!=u);
ans+=dp(cnt);
}
}
}
cout<<ans;
return ;
}

BZOJ 1791 岛屿(环套树+单调队列DP)的更多相关文章

  1. BZOJ3242 [Noi2013]快餐店 【环套树 + 单调队列dp】

    题目链接 BZOJ3242 题解 题意很清楚,找一点使得最远点最近 如果是一棵树,就是直径中点 现在套上了一个环,我们把环单独拿出来 先求出环上每个点外向树直径更新答案,并同时求出环上每个点外向的最远 ...

  2. BZOJ1791 [Ioi2008]Island 岛屿[基环树+单调队列优化DP]

    基环树直径裸题. 首先基环树直径只可能有两种形式:每棵基环树中的环上挂着的树的直径,或者是挂在环上的两个树的最大深度根之间的距离之和. 所以,先对每个连通块跑一遍,把环上的点找出来,然后对环上每个点跑 ...

  3. bzoj 1791: [Ioi2008]Island 岛屿【基环树+单调队列优化dp】

    我太菜了居然调了一上午-- 这个题就是要求基环树森林的基环树直径和 大概步骤就是找环->dp找每个环点最远能到达距离作为点权->复制一倍环,单调队列dp 找环是可以拓扑的,但是利用性质有更 ...

  4. 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP

    2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] D ...

  5. 1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP

    1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP 题意 用摄像机观察动物,有两个摄像机,一个可以放在奇数天,一个可以放在偶数天.摄像机在 ...

  6. BZOJ 1012 线段树||单调队列

    非常裸的线段树  || 单调队列: 假设一个节点在队列中既没有时间优势(早点入队)也没有值优势(值更大),那么显然不管在如何的情况下都不会被选为最大值. 既然它仅仅在末尾选.那么自然能够满足以上的条件 ...

  7. CF480E Parking Lot(单调队列+dp然鹅并不是优化)

    (全英文题面所以直接放化简题意) 题意:在一个二维平面内,初始有一些点,然后每个时间点加入一些点,对每个时间点求平面内最大的无障碍正方形 (这次的题目是真的神仙啊...) 首先,考虑暴力,如果对每一个 ...

  8. POJ 3017 单调队列dp

    Cut the Sequence Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8764   Accepted: 2576 ...

  9. [TyvjP1313] [NOIP2010初赛]烽火传递(单调队列 + DP)

    传送门 就是个单调队列+DP嘛. ——代码 #include <cstdio> ; , t = , ans = ~( << ); int q[MAXN], a[MAXN], f ...

随机推荐

  1. Java面向对象之抽象方法&接口

    在开始写抽象类之前,有一个问题我觉得想清楚会对理解抽象类很有帮助:那就是为什么要设计抽象类? 难道用类还不够么,为什么要设计出抽象类这样一个东西.我们可以换个角度来理解,就是有些类本来就是不应该被实例 ...

  2. CF 1042 F. Leaf Sets

    F. Leaf Sets http://codeforces.com/contest/1042/problem/F 题意: 将所有的叶子节点分配到尽量少的集合,一个可行的集合中两两叶子节点的距离< ...

  3. andriod 学习三 使用android资源

    3.1 android框架中有许多资源,包括布局,字符串,位图,图片....,使用资源之前需要在相应的资源文件中定义资源,然后编译程序时ADT将定义的资源转换成java类并给予唯一的id,而代码中需要 ...

  4. 【picker】选择器组件说明

    picker从底部弹起选择器组件 组件细节: 1) 该组件有五种类型,分别是普通选择器.多列选择器.时间选择器.日期选择器.省市区选择器. 2) 组件内必需包裹内容,不然无法弹出选项 <!-- ...

  5. 213. String Compression【LintCode java】

    Description Implement a method to perform basic string compression using the counts of repeated char ...

  6. 数据库Mysql的学习(七)-自定义函数和流程控制

    DELIMITER // (设置结束符 其实我也不太明白为啥要这样 记住就行把) CREATE FUNCTION ym_date(mydate DATE) (创建函数 函数名字(参数)) ) (指定函 ...

  7. day-17 L1和L2正则化的tensorflow示例

    机器学习中几乎都可以看到损失函数后面会添加一个额外项,常用的额外项一般有两种,一般英文称作ℓ1-norm和ℓ2-norm,中文称作L1正则化和L2正则化,或者L1范数和L2范数.L2范数也被称为权重衰 ...

  8. leetcode个人题解——#20 Valid Parentheses

    class Solution { public: bool isValid(string s) { stack<char> brackts; ; i < s.size(); i++) ...

  9. 在mesh client示例中加入spi_slave接口(without IDE)

    在mesh client示例中加入spi_slave接口(without IDE) 主要是理解cmake构建的过程,然后修改工程中的inlcude路径及c源文件. 1. 解压mesh_sdk unzi ...

  10. .Net并行编程 - Reactive Extensions(Rx)并发浅析

    关于Reactive Extensions(Rx) 关于Reactive Extensions(Rx),先来看一下来自微软的官方描述: The Reactive Extensions (Rx) is ...