P2495 [SDOI2011] 탈퇴 (가상 트리 + DP)

제목 설명

전쟁에서 N-1로 구성된 n 개의 섬과 다리에 의해 전장마다 두 섬 사이에 하나 개의 경로 만 거기 있는지 확인합니다. 이제 우리 군은 섬에 대한 제 1의 적의 본부를 감지 할 수있다, 그들은 전투, 눈에 군사적 승리를 유지하기 위해 충분한 에너지를 가지고 있지 않습니다. 에너지 적 접근을 방지하기 위해, 다른 섬의 K에 풍부한 에너지를 가지고 알려진 우리의 군사 임무의 일부는 적의 어떤 에너지가 풍부한 섬에 도달 할 수 있도록 다리를 폭파하는 것입니다. 때문에 다른 재료와 다리의 다른 구조로, 다리는, 다른 서로 다른 가격이 날려 총 비용을 최소화하기 위해 목표를 충족시키면서 우리의 군사를 희망합니다.

조사 부서는 신비한 적 기계가 있음을 발견했다. 군대는 모든 에너지를 차단 후에도, 그들은 또한 그 기계를 사용할 수 있습니다. 기계 생성 효과는 다리를 폭파하기 위해 군사를 모두 해결되지 않습니다 및 자원의 분포 난수를 다시 것입니다 (하지만 당신은 자원이 섬에 제 1 호에 배포되지 않도록 보장 할 수 있습니다). 그러나 조사는 또한 부서는이 기계 m 시간을 사용할 수 있다는 것을 발견, 그래서 우리는 단지 각 작업을 완료해야합니다.

입력 형식

제 라인 정수 n은, 섬의 수를 나타낸다.

다음에, N-1 세 정수 선 U, V는 W는 U가되도록 직접 고려하여 연결된 섬의 수 및 섬 다리 번호 v에 C를 나타내는 <= U, V <= N-1 <= 그 C <= 100,000.

N + 1 번째 행, 정수 m은 적 시스템의 대표적인 숫자를 사용할 수있다.

다음 m 라인 각각 정수 KI, 제 i의 대신에, KI 섬 풍부한 자원을 가지고, 다음 정수 k 값 H1은 H2는 ... HK는 자원이 풍부한 섬의 수를 나타낸다.

출력 형식

이 작업 당 최소의 비용을 나타내는 m 출력 라인을 가지고있다.

샘플 입출력

입력 # 1
10 
1 5 13 
1 9 6 
2 1 19 
2 4 8 
2 3 91 
5 6 8 
7 4 5 
7 8 31 
10 9 7 
3 
2 6 10 
4 5 7 8 3 
3 6 9 4
출력 # 1
12 
32 
22

설명 / 팁

[데이터] 규모 규칙

10 %, 2 <=는 N <= 10,1 <= m <= 5,1 <= KI <= N-1이 데이터

20 %의 데이터 (2) <= N <= 100,1 <= m <= 100,1 <= KI <= 분 (10, N-1)

40 %의 데이터 (2) <= N <= 1000, m> = 1, 시그마 (KI) <= 500000,1 <= KI <= 분 (15, N-1)

데이터의 100 %, 2 <= N <= 250,000, m> = 1, 시그마 (KI) <= 500000,1 <= KI <= N-1이

 

해결책:

 

각 쿼리 키포인트 들어, 두 지점 사이의 가상 에지 가중치의 설정은, 두 지점 사이의 원래 트리 경로에 낮은 값이고

DP 시간이 포인트가 핵심이다, 플러스 측의 권리

그렇지 않은 경우, 최소 추가 (오른쪽, 그것은 오프이 하위 트리 아들의 모든 주요 지점 소요)

 

암호:

 

#include"iostream"
#include"algorithm"
#include"vector"
#include"stdio.h"
using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)

const int N = 250007;


vector<int> RG[N],VG[N];
int U[N],V[N],C[N];
int dfn[N],deep[N];
ll me[N];
int fa[N][20];
int stk[N],top;
int idq[N],mark[N];
int n,m,idx;
int f[N][20];
int dp[N];
struct aa
{
    int so;
    int w;
};
vector<aa> G[N];

int LCA(int u,int v)
{
    if(deep[u] < deep[v]) swap(u,v);
    int delta = deep[u] - deep[v];
    for(int i = 19; i >= 0; --i)
    {
        if((delta >> i) & 1) u = fa[u][i];
    }
    for(int i = 19; i >= 0; --i)
    {
        if(fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];
    }
    if(u == v) return u;
    return fa[u][0];
}

int DIS(int u,int v)
{
    if(deep[u] < deep[v]) swap(u,v);
    int delta = deep[u] - deep[v];
    int ans=1e16;
    for(int i = 19; i >= 0; --i)
    {
        if((delta >> i) & 1) ans=min(ans,f[u][i]),u = fa[u][i];
    }
    if(u == v) return ans;
    for(int i = 19; i >= 0; --i)
    {
        if(fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];
    }

    return fa[u][0];
}

void insert2(int u)
{
    if(top == 1)
    {
        stk[++top] = u;
        return;
    }
    int lca = LCA(u,stk[top]);
    if(lca == stk[top])
    {
        stk[++top] = u;
        return ;
    }
    while(top > 1 && dfn[lca] <= dfn[stk[top-1]])
    {
        G[stk[top-1]].push_back({stk[top],DIS(stk[top],stk[top-1])});
        --top;
    }
    if(lca != stk[top])
    {
        G[lca].push_back({stk[top],DIS(stk[top],lca)});
        stk[top] = lca;
    }
    stk[++top] = u;
}

ll dp2(int x)
{
    ll cost=0;
    int len=G[x].size();
    for(int j=0;j<len;j++)
    {
        aa i=G[x][j];
        if(mark[i.so])cost+=i.w;
        else cost+=min(1ll*i.w,dp2(i.so));
    }
    return cost;

}
void Clear(int x)
{
    int len=G[x].size();
     for(int j=0;j<len;j++)
    {
        aa i=G[x][j];
        Clear(i.so);

    }
    G[x].clear();
}

/***********************************/


void dfs(int u)
{
    dfn[u] = ++idx;
    deep[u] = deep[fa[u][0]] + 1;
    int len=RG[u].size();
    for(int j=0;j<len;j++)
    {
        int e=RG[u][j];
        int v = U[e] ^ V[e] ^ u;
        if(v == fa[u][0]) continue;
        me[v] = C[e];
        f[v][0]=C[e];
        if(u != 1 && me[u] < me[v]) me[v] = me[u];
        fa[v][0] = u;
        dfs(v);
    }
}


bool comp(int a,int b)
{
    return dfn[a] < dfn[b];
}
/***********************************/

#define sc(x) scanf("%d",&(x))

signed main()
{
    cin >> n;
    for(int i = 1; i < n; ++i)
    {
        sc(U[i]); sc(V[i]); sc(C[i]);
        RG[U[i]].push_back(i);
        RG[V[i]].push_back(i);
    }
    dfs(1);

    for(int t = 1; t <= 19; ++t) for(int i = 1; i <= n; ++i)
        {
            fa[i][t] = fa[fa[i][t-1]][t-1];
            if(fa[i][t])  f[i][t] = min(f[i][t-1] , f[fa[i][t-1]][t-1]);
        }

    cin >> m;
    for(int i = 0; i < m; ++i)
    {
        int sz;
        sc(sz);
        for(int j = 0; j < sz; ++j)
        {
            sc(idq[j]);
            mark[idq[j]] = 1;
        }
        sort(idq,idq+sz,comp);
        top = 0;
        stk[++top] = 1;
        for(int j = 0; j < sz; ++j) insert2(idq[j]);
        while(top > 0)
        {
            G[stk[top-1] ].push_back({stk[top],DIS(stk[top-1],stk[top])});
            top--;
        }
        printf("%lld\n",dp2(1));
        Clear(1);
        for(int j = 0; j < sz; ++j) mark[idq[j]] = 0;

    }
    return 0;
}

  

 

 

 

 

 

추천

출처www.cnblogs.com/zhangbuang/p/11310467.html