[2007] IOI training path

Tree-like pressure dp + dp

Topic Link

First of all, you can not delete edges form a tree (nonsense)

So we put the tree to get it out.

due to

In order to ensure the same intensity of their training, they have to choose a path with an even number of roads.

So the rest of the non-tree edge end points constitute a dual ring, then this non-tree edge is certain to be deleted.

also because

I never have been halfway across the city, and never ride twice on the same road (regardless of whether the same direction)

Then will be deleted after the formation of even non-tree ring side, we can see that if there are two odd tree ring side relative weight, apparently it is not legitimate.

Therefore, each side of the tree it will only be traversed once.

So, we can get upside down. That select several pieces of non-tree edge, such that each side of the tree it will only traversed once, and so that these edge weights as large as possible.

Take a look at the title

In addition, each city is up to 101,010 endpoints road

In this regard, consider shaped pressure: \ (DP [X] [STA] \) indicates that the current node is x, which is the state of the selected son sta (1 showing selected) and the maximum right side.

Then for a non-tree edge, there are two decisions:

1. vote for it. (See illustration)

That is, back to a point when we remove it as lca all non-tree edges, and then pre-Val snail formula (n anyway before 1000)

Then transferred just fine.

2. Do not vote for it.

This is relatively easy up.

For a state sta, we just need to find the selected son, then dp values ​​of these sons of tired and get over it.

Code:

#include<bits/stdc++.h>
#define MAXN 10010
using namespace std;
int n,m,tot,head[MAXN],cnt,pre[MAXN][20],deep[MAXN],lg[MAXN],dp[1050][1050],num[1010][1010],Cnt[MAXN],ansSum,ans;
struct sgt {
    int st,ed,v,lca,sum,X,Y;
} E[MAXN];
struct node {
    int ed,last;
} G[MAXN<<1];
vector<int> Q[MAXN];
void Add(int st,int ed) {
    tot++;
    G[tot]=node {ed,head[st]};
    head[st]=tot;
}
void DFS(int x,int fa){
    deep[x]=deep[fa]+1;
    pre[x][0]=fa;
    for(int i=1;(1<<i)<=deep[x];i++)pre[x][i]=pre[pre[x][i-1]][i-1];
    for(int i=head[x];i;i=G[i].last){
        int t=G[i].ed;
        if(t==fa)continue;
        DFS(t,x);
    }
}
int LCA(int x,int y){
    if(deep[x]<deep[y])swap(x,y);
    while(deep[x]>deep[y])x=pre[x][lg[deep[x]-deep[y]]-1];
    if(x==y)return x;
    for(int i=lg[deep[x]]-1;i>=0;i--){
        if(pre[x][i]==pre[y][i])continue;
        x=pre[x][i],y=pre[y][i];
    }
    return pre[x][0];
}
int jump(int x,int y,int id){
    if(x==y)return 0;
    int sonx=x;
    x=pre[x][0];
    while(x!=y){
        E[id].sum+=dp[x][((1<<Cnt[x])-1)^num[x][sonx]];
        sonx=x;
        x=pre[x][0];
    }
    return sonx;
}
void solve(int x,int fa){
    for(int i=head[x];i;i=G[i].last){
        int t=G[i].ed;
        if(t==fa)continue;
        num[x][t]=1<<Cnt[x];
        Cnt[x]++;
        solve(t,x);
    }
    for(int i=0;i<Q[x].size();i++){
        int id=Q[x][i],st=E[id].st,ed=E[id].ed;
        E[id].sum=dp[st][(1<<Cnt[st])-1]+dp[ed][(1<<Cnt[ed])-1]+E[id].v;
        E[id].X=jump(st,x,id);
        E[id].Y=jump(ed,x,id);
    }
    for(int i=0;i<(1<<Cnt[x]);i++){
        int res=0;
        for(int j=head[x];j;j=G[j].last){
            int t=G[j].ed;
            if(t==fa)continue;
            if(num[x][t]&i)res+=dp[t][(1<<Cnt[t])-1];
        }
        dp[x][i]=max(dp[x][i],res);
    }
    for(int i=0;i<(1<<Cnt[x]);i++){
        for(int j=0;j<Q[x].size();j++){
            int id=Q[x][j],X=E[id].X,Y=E[id].Y;
            if((num[x][X]&i)||(num[x][Y]&i))continue;
            dp[x][i|num[x][X]|num[x][Y]]=max(dp[x][i|num[x][X]|num[x][Y]],dp[x][i]+E[id].sum);
        }
    }
}
int main() {
    for(int i=1;i<=MAXN-10;i++)lg[i]=lg[i-1]+((1<<lg[i-1])==i);
    scanf("%d %d",&n,&m);
    for(int x,y,z,i=1; i<=m; i++) {
        scanf("%d %d %d",&x,&y,&z);
        if(z==0) {
            Add(x,y);
            Add(y,x);
        }
        else {
            cnt++;
            E[cnt]=sgt{x,y,z};
        }
    }
    DFS(1,0);
    for(int i=1;i<=cnt;i++){
        E[i].lca=LCA(E[i].st,E[i].ed);
        if((deep[E[i].st]+deep[E[i].ed]-2*deep[E[i].lca])&1)ans+=E[i].v;    
        else Q[E[i].lca].push_back(i),ansSum+=E[i].v;
    }
    solve(1,0);
    ans+=ansSum-dp[1][(1<<Cnt[1])-1];
    cout<<ans;
    return 0;
}

Guess you like

Origin www.cnblogs.com/SillyTieT/p/11486037.html