[BZOJ3572] [Hnoi2014] 세계수(허수+수형dp+이분+lca)
제목 설명
전송문
문제풀이
먼저 허수를 세우면 변권은 원래 나무의 거리라는 문제입니다. 제 dp의 방법은 매우 어리석습니다. f(i)는 i의 아버지 쪽에서 나가(i의 아버지를 거쳐야 한다) 도착하는 관건의 최단길 fp(i)는 최단길 점 g(i)는 i에서 i의 자수까지 도착하는 관건의 최단길 gp(i)는 최단길 점을 표시하고 이 두 개는 서로 이동합니다.
dp가 끝난 후에 허수 위의 모든 변(u, v)을 매거한다. u에서 관건점까지의 최단길과 v에서 관건점까지의 최단길을 알고 이 변두리의 어떤 점이 u로 돌아가는지, 어떤 점이 v로 돌아가는지 짜증나게 2분을 계산할 수 있기 때문이다. 그러나 징그러운 것은 통계 답안이다. 지어진 허수는 관건점과 그 lca만 포함하기 때문이다.각 점과 각 변두리에 다소 관건이 없는 서브트리가 있을 수 있습니다.
수업 두 시간 조정했는데.. 점심도 못 먹고.. 징그러워 죽겠어. 내가 너무 어리석어서 그런가 봐.
코드
#include
#include
#include
#include
#include
using namespace std;
#define N 600005
#define sz 19
int n,q,m,dfs_clock,inf;
int tot,point[N],nxt[N],v[N],last[N];
int in[N],out[N],h[N],size[N],cnt[N],stack[N],top,st[N][sz+3],key[N],flag[N];
int qu[N],f[N],fp[N],g[N],gp[N],Son[N],pt[N],goal[N],ans[N];
void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
void build(int x,int fa)
{
in[x]=++dfs_clock;h[x]=h[fa]+1;size[x]=1;
for (int i=1;i1]][i-1];
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
st[v[i]][0]=x;
build(v[i],x);
size[x]+=size[v[i]];
}
out[x]=dfs_clock;
}
int cmp(int a,int b)
{
return in[a]<in[b];
}
int lca(int x,int y)
{
if (h[x]int k=h[x]-h[y];
for (int i=0;iif ((k>>i)&1) x=st[x][i];
if (x==y) return x;
for (int i=sz-1;i>=0;--i)
if (st[x][i]!=st[y][i]) x=st[x][i],y=st[y][i];
return st[x][0];
}
void sontofa(int x)
{
if (key[x]==q) g[x]=0,gp[x]=x;
for (int i=point[x];i;i=nxt[i])
{
sontofa(v[i]);
if (g[v[i]]+last[v[i]]else if (g[v[i]]+last[v[i]]==g[x]&&gp[v[i]]int find(int x,int k)
{
for (int i=0;iif ((k>>i)&1) x=st[x][i];
return x;
}
void calc(int len,int fa,int son)
{
int minson=g[son],minfa=f[son]-len;
if (minson&&minfa&&(len+minfaint p=find(son,len-1);
goal[fa]=goal[son]=fp[son];
ans[fp[son]]+=size[p]-size[son];
return;
}
if (minson&&minfa&&(minson+lenint p=find(son,len-1);
goal[fa]=goal[son]=gp[son];
ans[gp[son]]+=size[p]-size[son];
return;
}
int l=-1,r=len,mid,final=-1;
while (l<=r)
{
if (l==r&&l==-1)
{
final=-1;
break;
}
mid=(l+r)>>1;
if (mid+minson1;
else r=mid-1;
}
if (final==len)
{
int p=find(son,len-1);
goal[fa]=goal[son]=gp[son];
ans[gp[son]]+=size[p]-size[son];
return;
}
if (final==-1)
{
int p=find(son,len-1);
goal[fa]=goal[son]=fp[son];
ans[fp[son]]+=size[p]-size[son];
return;
}
int p=find(son,len-1),t=find(son,final);
goal[fa]=fp[son];goal[son]=gp[son];
ans[fp[son]]+=size[p]-size[t];
ans[gp[son]]+=size[t]-size[son];
return;
}
void fatoson(int x)
{
if (key[x]==q)
{
for (int i=point[x];i;i=nxt[i])
f[v[i]]=last[v[i]],fp[v[i]]=x;
}
else
{
Son[0]=0;
for (int i=point[x];i;i=nxt[i]) Son[++Son[0]]=v[i];
int Min=inf,Minp=0;
for (int i=1;i<=Son[0];++i)
{
if (f[x]+last[Son[i]]else if (f[x]+last[Son[i]]==f[Son[i]]&&fp[x]if (Min+last[Son[i]]else if (Min+last[Son[i]]==f[Son[i]]&&Minpif (g[Son[i]]+last[Son[i]]else if (g[Son[i]]+last[Son[i]]==Min&&gp[Son[i]]0;
for (int i=Son[0];i>=1;--i)
{
if (Min+last[Son[i]]else if (Min+last[Son[i]]==f[Son[i]]&&Minpif (g[Son[i]]+last[Son[i]]else if (g[Son[i]]+last[Son[i]]==Min&&gp[Son[i]]for (int i=point[x];i;i=nxt[i])
{
fatoson(v[i]);
calc(last[v[i]],x,v[i]);
}
}
void solve()
{
sontofa(1);
fatoson(1);
for (int i=1;i<=pt[0];++i)
ans[goal[pt[i]]]+=cnt[pt[i]];
for (int i=1;i<=m;++i)
printf("%d ",ans[qu[i]]);puts("");
}
int main()
{
scanf("%d",&n);
for (int i=1;iint x,y;scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
build(1,0);
scanf("%d",&q);
memset(point,0,sizeof(point));
memset(g,127,sizeof(g));inf=g[0];
memset(f,127,sizeof(f));
while (q)
{
scanf("%d",&m);
for (int i=1;i<=m;++i)
{
scanf("%d",&pt[i]);
qu[i]=pt[i];
key[pt[i]]=flag[pt[i]]=q;
goal[pt[i]]=pt[i];
}
sort(pt+1,pt+m+1,cmp);pt[0]=m;
for (int i=2;i<=m;++i)
{
int r=lca(pt[i-1],pt[i]);
if (flag[r]!=q)
flag[r]=q,pt[++pt[0]]=r;
}
if (flag[1]!=q) flag[1]=q,pt[++pt[0]]=1;
sort(pt+1,pt+pt[0]+1,cmp);
tot=0;stack[top=1]=1;cnt[1]=size[1];
for (int i=2;i<=pt[0];++i)
{
while (in[pt[i]]<in[stack[top]]||in[pt[i]]>out[stack[top]])
--top;
add(stack[top],pt[i]);
last[pt[i]]=h[pt[i]]-h[stack[top]];
int r=find(pt[i],h[pt[i]]-h[stack[top]]-1);
cnt[stack[top]]-=size[r];
stack[++top]=pt[i];cnt[pt[i]]=size[pt[i]];
}
solve();
for (int i=1;i<=pt[0];++i)
{
int x=pt[i];
point[x]=fp[x]=gp[x]=cnt[x]=ans[x]=last[x]=goal[x]=0;
f[x]=g[x]=inf;
}
--q;
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
49일차 - 2022.04.20Baekjoon에서 문제풀이 1) 문제 : 첫째 줄에는 별 1개, 둘째 줄에는 별 2개, N번째 줄에는 별 N개를 찍는 문제/ 첫째 줄에 N(1 ≤ N ≤ 100)이 주어진다. 첫째 줄부터 N번째 줄까지 차례대로 별...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.