一个显而易见的方法是考虑点的贡献,一次dfs记录到所有根节点不考虑匹配的答案,再一次dfs反向推出答案
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <map> #include <set> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; const int MAXBUF=10000;char buf[MAXBUF],*ps=buf,*pe=buf+1; inline bool isdigit(const char& n) {return (n>='0'&&n<='9');} inline void rnext(){if(++ps==pe)pe=(ps=buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);} template <class T> inline bool in(T &ans){ #ifdef VSCode ans=0;T f=1;register char c; do{c=getchar();if ('-'==c)f=-1;}while(!isdigit(c)&&c!=EOF); if(c==EOF)return false;do{ans=(ans<<1)+(ans<<3)+c-48; c=getchar();}while(isdigit(c)&&c!=EOF);ans*=f;return true; #endif #ifndef VSCode ans =0;T f=1;if(ps==pe)return false;do{rnext();if('-'==*ps)f=-1;} while(!isdigit(*ps)&&ps!=pe);if(ps==pe)return false;do{ans=(ans<<1)+(ans<<3)+*ps-48; rnext();}while(isdigit(*ps)&&ps!=pe);ans*=f;return true; #endif }const int MAXOUT=10000; char bufout[MAXOUT], outtmp[50],*pout = bufout, *pend = bufout+MAXOUT; inline void write(){fwrite(bufout,sizeof(char),pout-bufout,stdout);pout = bufout;} inline void out_char(char c){*(pout++)=c;if(pout==pend)write();} inline void out_str(char *s){while(*s){*(pout++)=*(s++);if(pout==pend)write();}} template <class T>inline void out_int(T x) {if(!x){out_char('0');return;} if(x<0)x=-x,out_char('-');int len=0;while(x){outtmp[len++]=x%10+48;x/=10;}outtmp[len]=0; for(int i=0,j=len-1;i<j;i++,j--) swap(outtmp[i],outtmp[j]);out_str(outtmp);} template<typename T, typename... T2> inline int in(T& value, T2&... value2) { in(value); return in(value2...); } #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second #define Vec Point typedef vector<int> VI; const double eps = 1e-9; const int maxn = 2e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,K,temp,cnt; bool sp[maxn]; LL head[maxn],MAX[maxn],id[maxn],sum[maxn],ans[maxn]; struct Edge{ int to,next; }edge[maxn * 2]; void init(){Mem(head,0); cnt = 0;} void add(int u,int v){edge[++cnt].to = v; edge[cnt].next = head[u];head[u] = cnt;} LL dfs(int x,int last){ sum[x] = 0; for(int i = head[x] ; i; i = edge[i].next){ int v = edge[i].to; if(v == last) continue; int t = dfs(v,x); if(t > MAX[x]){ MAX[x] = t; id[x] = v; } sum[x] += t; ans[x] += ans[v]; } ans[x] += sum[x]; sum[x] += sp[x]; return sum[x]; } LL getans(int x,int c){ sum[x] -= c; MAX[x] -= c; if(MAX[x] * 2 <= sum[x]){ return ans[x]; }else{ int v = id[x]; return ans[x] - ans[v] - sum[v] + getans(v,sum[x] - MAX[x] + c) + sum[x] - MAX[x] + c; } } LL solve(){ int root = 1; dfs(root,-1); // For(i,1,N){ // cout << i << ":" << sum[i] << " " << MAX[i] << endl; // } return getans(root,0); } int main() { in(N,K); For(i,1,2 * K){ in(temp); sp[temp] = 1; } For(i,1,N - 1){ int u,v; in(u,v); add(u,v); add(v,u); } Prl(solve()); #ifdef VSCode write(); system("pause"); #endif return 0; }
这并不是很好写,另一个不显而易见但是很好写很好对的方法是考虑边的贡献,一条边两边的点分别是x和2K - x,由于路线尽可能的长,较小的那一边一定要加上较大的那一边,所以每条边经过一次,同时更新ans即可
#include <map> #include <set> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; const int MAXBUF=10000;char buf[MAXBUF],*ps=buf,*pe=buf+1; inline bool isdigit(const char& n) {return (n>='0'&&n<='9');} inline void rnext(){if(++ps==pe)pe=(ps=buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);} template <class T> inline bool in(T &ans){ #ifdef VSCode ans=0;T f=1;register char c; do{c=getchar();if ('-'==c)f=-1;}while(!isdigit(c)&&c!=EOF); if(c==EOF)return false;do{ans=(ans<<1)+(ans<<3)+c-48; c=getchar();}while(isdigit(c)&&c!=EOF);ans*=f;return true; #endif #ifndef VSCode ans =0;T f=1;if(ps==pe)return false;do{rnext();if('-'==*ps)f=-1;} while(!isdigit(*ps)&&ps!=pe);if(ps==pe)return false;do{ans=(ans<<1)+(ans<<3)+*ps-48; rnext();}while(isdigit(*ps)&&ps!=pe);ans*=f;return true; #endif }const int MAXOUT=10000; char bufout[MAXOUT], outtmp[50],*pout = bufout, *pend = bufout+MAXOUT; inline void write(){fwrite(bufout,sizeof(char),pout-bufout,stdout);pout = bufout;} inline void out_char(char c){*(pout++)=c;if(pout==pend)write();} inline void out_str(char *s){while(*s){*(pout++)=*(s++);if(pout==pend)write();}} template <class T>inline void out_int(T x) {if(!x){out_char('0');return;} if(x<0)x=-x,out_char('-');int len=0;while(x){outtmp[len++]=x%10+48;x/=10;}outtmp[len]=0; for(int i=0,j=len-1;i<j;i++,j--) swap(outtmp[i],outtmp[j]);out_str(outtmp);} template<typename T, typename... T2> inline int in(T& value, T2&... value2) { in(value); return in(value2...); } #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second #define Vec Point typedef vector<int> VI; const double eps = 1e-9; const int maxn = 2e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,K,temp,cnt; bool sp[maxn]; LL head[maxn],MAX[maxn],id[maxn],sum[maxn],ans[maxn],Ans; struct Edge{ int to,next; }edge[maxn * 2]; void init(){Mem(head,0); cnt = 0;} void add(int u,int v){edge[++cnt].to = v; edge[cnt].next = head[u];head[u] = cnt;} LL dfs(int x,int last){ sum[x] = sp[x]; for(int i = head[x] ; i; i = edge[i].next){ int v = edge[i].to; if(v == last) continue; int t = dfs(v,x); Ans += min(t,2 * K - t); sum[x] += t; } return sum[x]; } LL solve(){ int root = 1; dfs(root,-1); return Ans; } int main() { in(N,K); For(i,1,2 * K){ in(temp); sp[temp] = 1; } For(i,1,N - 1){ int u,v; in(u,v); add(u,v); add(v,u); } Prl(solve()); #ifdef VSCode write(); system("pause"); #endif return 0; }