bzoj 1791, P4381 - [IOI 2008] Island [기 환 수, 나무형 dp, 단조 로 운 대열 dp, 나무의 직경]
평가 기록:https://www.luogu.org/recordnew/lists?uid=52918&pid=P4381
제목 의 대의
n 개의 섬 이 있 고 n 개의 방향 이 없다.지나 가 는 길 과 섬 은 다시 가면 안 되 고 배 를 탈 수 있다.배 를 타 는 것 은 이전에 사용 하지 않 았 던 배 와 도로 가 그 지점 에 도착 해 야 배 를 탈 수 있다 고 요구한다.
최 장 을 구하 면 얼마나 멀리 갈 수 있 습 니까?
문제 풀이 의 사고 방향.
우선 이것 은 기 환 나무 숲 으로 배 를 타 는 규정 에 따라 사실은 모든 기 환 나 무 는 한 번 만 걸 을 수 있다 는 것 이다.이때 우 리 는 답 이 모든 기 환 나무의 지름 의 합 이라는 것 을 알 수 있다.그런 후에 우 리 는 지름 을 어떻게 계산 할 것 인 가 를 고려 했다.
고 리 를 뿌리 로 삼다.우 리 는 답 이 두 가지 만 가능 하 다 는 것 을 발견 했다.
경과 근
뿌리 를 거치 지 않다.
우 리 는 뿌리 를 거치 지 않 고 f x f 를 계산 하 는 것 을 고려 합 니 다.x fx (f x f x fx 는 x 서브 트 리 에서 x 에서 가장 먼 점 의 거 리 를 나타 낸다) 그리고 나무의 지름 을 구 하 는 방법 으로 뿌리 아래 의 모든 나무의 지름 을 구하 고 기록 합 니 다.그리고 우 리 는 뿌리 를 거 친 것 을 계산한다.링 의 노드 가 s s 집합 이 라 고 가정 하면 정 답 은 m a x (f s i + f s j + d i s i ∼ j) max (f {s i} + f {s j} + dis {i \ sim j}) max (fsi + fsj + disi ∼ j) dis 는 링 위의 i 에서 j 까지 의 가장 먼 거 리 를 나타 낸다.우 리 는 단조 로 운 대기 열 dp 를 통 해 답 을 계산 해 낼 수 있다.
code
#include
#include
#include
#include
#define N 1000010
#define lls long long
using namespace std;
struct node{
int to,next,w;
}a[2*N];
int n,x,y,tot,t;
lls ls[N],in[N],cr[2*N],v[N],k[N],f[N],d[N],dis[2*N],ans,q[2*N];
void addl(int x,int y,int w)//
{
a[++tot].to=y;
a[tot].w=w;
a[tot].next=ls[x];
ls[x]=tot;
in[y]++;
}
void dfs(int now,int k){
v[now]=k;
for (int i=ls[now];i;i=a[i].next){
int y=a[i].to;
if(!v[y]) dfs(y,k);
}
}//
void topsort(){
int l=0,r=0;
for (int i=1;i<=n;i++)
if(in[i]==1) q[++r]=i;
while(l<r) {
int now=q[++l];
for (int i=ls[now];i;i=a[i].next){
int y=a[i].to;
if(in[y]>1){
in[y]--;
d[v[now]]=max(d[v[now]],f[now]+f[y]+a[i].w);
f[y]=max(f[y],f[now]+a[i].w);
if(in[y]==1) q[++r]=y;
}
}
}
}//
void dp(int t,int x){
int m=0,y=x,i;
do{
cr[++m]=f[y];in[y]=1;
for(i=ls[y];i;i=a[i].next){
if(in[a[i].to]>1){
dis[m+1]=dis[m]+a[i].w;
y=a[i].to;
break;
}
}
}while(i);//
if(m==2){
int l=0;
for (int i=ls[y];i;i=a[i].next)
if(a[i].to==x) l=max(l,a[i].w);
d[t]=max(d[t],f[x]+f[y]+l);
return;
}//
for(int i=ls[y];i;i=a[i].next){
if(a[i].to==x) {
dis[m+1]=dis[m]+a[i].w;
break;
}
}//
for (int i=1;i<=m;i++){
cr[i+m]=cr[i];
dis[m+i]=dis[m+1]+dis[i];
}//
int l=1,r=0;
q[++r]=1;
for (int i=2;i<2*m;i++){
while(l<=r&&i-q[l]>=m)
l++;
d[t]=max(dis[i]-dis[q[l]]+cr[i]+cr[q[l]],d[t]);
while(l<=r&&cr[q[r]]+dis[i]-dis[q[r]]<=cr[i])
r--;
q[++r]=i;
}// dp
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d",&x,&y);
addl(i,x,y);
addl(x,i,y);
}
for (int i=1;i<=n;i++)
if (!v[i]) dfs(i,++t);
topsort();
for (int i=1;i<=n;i++){
if(in[i]>1&&!k[v[i]]) {
k[v[i]]=1;
dp(v[i],i);
ans+=d[v[i]];
}
}
printf("%lld",ans);
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
【경쟁 프로 전형적인 90문】008의 해설(python)의 해설 기사입니다. 해설의 이미지를 봐도 모르는 (이해력이 부족한) 것이 많이 있었으므로, 나중에 다시 풀었을 때에 확인할 수 있도록 정리했습니다. ※순차적으로, 모든 문제의 해설 기사를 들어갈 예정입니다. 문자열...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.