Spoj 1825 Freetour2
点分治第二题,分治过程写的比较熟练了,但搞答案的时候还是想了好久,写了好久.......
主要解释一下求g的那块吧:
首先dep[i]表示rot的第i个儿子的子树里黑点最多的路径的的黑点数。
黑点限制是K,我们可以求出rot的每一个儿子i黑点数为j的最大长度g[i,j],然后每次求出一个j1+j2<=K,且g[i1,j1]+g[i2,j2]最大的。
如果我们枚举i2,那么只需要求出一个可以和i2配并且最长的i1就行了。这个可以用个什么数据结构维护,也可以“暴力”。由于顺序是对答案没有影响的,那么我们按照dep升序排序,然后按照这个顺序计算,mg[j]表示前i个点的g[j]的最大值,如果维护好mg,就可以用g+mg来更新答案了。最恶心就是更新答案这里,假设当前枚举到了g[j],我们需要找到一个≤K-j-black[rot]的,但是我们不能直接用mg[K-j-black[rot]],因为前面i-1个点可能没有达到K-j-black[rot]个黑点的,这样我们得用第i-1个点的dep。就说这些吧,其他地方看论文就行了。
Freetour
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define inf 2147483647 7 #define maxn 420000 8 using namespace std; 9 10 struct et 11 { 12 int s,t,val,next; 13 }e[maxn]; 14 int fa[maxn],fir[maxn],size[maxn]; 15 int dep[maxn],son[maxn],g[maxn],mg[maxn],way[maxn]; 16 bool ex[maxn],black[maxn]; 17 int n,m,p,tot,ans,num; 18 19 void dfs(int now) 20 { 21 size[now]=1; 22 for (int j=fir[now];j;j=e[j].next) 23 { 24 int k=e[j].t; 25 if (k!=fa[now]) 26 { 27 fa[k]=now; 28 dfs(k); 29 size[now]+=size[k]; 30 } 31 } 32 } 33 34 void choose(int &rot) 35 { 36 int now,mx=0; 37 for (int j=fir[rot];j;j=e[j].next) 38 { 39 int k=e[j].t; 40 if (ex[k]&&k!=fa[rot]&&size[k]>mx) 41 { 42 mx=size[k]; 43 now=k; 44 } 45 } 46 if (mx>num/2) 47 { 48 size[rot]-=size[now]; 49 size[now]=num; 50 fa[rot]=now; 51 fa[now]=0; 52 choose(rot=now); 53 } 54 } 55 56 int getdep(int now) 57 { 58 int tmp=0; 59 for (int j=fir[now];j;j=e[j].next) 60 { 61 int k=e[j].t; 62 if (ex[k]&&k!=fa[now]) tmp=max(tmp,getdep(k)); 63 } 64 return black[now]+tmp; 65 } 66 67 int getway(int now,int sum,int dis) 68 { 69 g[sum]=max(g[sum],dis); 70 for (int j=fir[now];j;j=e[j].next) 71 { 72 int k=e[j].t; 73 if (ex[k]&&k!=fa[now]) getway(k,sum+black[k],dis+e[j].val); 74 } 75 } 76 77 bool cmp(int a,int b) 78 { 79 return dep[e[a].t]<dep[e[b].t]; 80 } 81 82 void solve(int rot) 83 { 84 if (num==1) return; 85 choose(rot); 86 int sum=0; 87 for (int j=fir[rot];j;j=e[j].next) 88 { 89 int k=e[j].t; 90 if (ex[k]) sum++,dep[k]=getdep(k),way[sum]=j; 91 } 92 sort(way+1,way+sum+1,cmp); 93 for (int i=0;i<=dep[e[way[sum]].t];i++) mg[i]=-inf; 94 for (int i=1;i<=sum;i++) 95 { 96 int k=e[way[i]].t; 97 for (int j=0;j<=dep[k];j++) g[j]=-inf; 98 getway(k,black[k],e[way[i]].val); 99 if (i!=1) 100 { 101 for (int j=0;j<=p-black[rot]&&j<=dep[k];j++) 102 { 103 int len=min(p-black[rot]-j,dep[e[way[i-1]].t]); 104 if (mg[len]==-inf) break; 105 if (g[j]!=-inf) ans=max(ans,mg[len]+g[j]); 106 } 107 } 108 for (int j=0;j<=dep[k];j++) 109 { 110 mg[j]=max(g[j],mg[j]); 111 if (j) mg[j]=max(mg[j-1],mg[j]); 112 if (j+black[rot]<=p) ans=max(ans,mg[j]); 113 } 114 } 115 ex[rot]=0; 116 for (int j=fir[rot];j;j=e[j].next) 117 { 118 int k=e[j].t; 119 if (ex[k]) 120 { 121 num=size[k]; 122 solve(k); 123 } 124 } 125 } 126 127 void add(int x,int y,int z) 128 { 129 e[++tot].s=x; e[tot].t=y; e[tot].val=z; e[tot].next=fir[x]; fir[x]=tot; 130 e[++tot].s=y; e[tot].t=x; e[tot].val=z; e[tot].next=fir[y]; fir[y]=tot; 131 } 132 133 int main() 134 { 135 //freopen("freetour.in","r",stdin); 136 scanf("%d %d %d",&n,&p,&m); 137 int x,y,z; 138 tot=0; 139 for (int i=1;i<=m;i++) 140 { 141 scanf("%d",&x); 142 black[x]=1; 143 } 144 for (int i=1;i<n;i++) 145 { 146 scanf("%d %d %d",&x,&y,&z); 147 add(x,y,z); 148 } 149 memset(ex,1,sizeof(ex)); 150 dfs(1); 151 num=n;ans=0; 152 solve(1); 153 printf("%d\n",ans); 154 }
AC without art, no better than WA !