【SPOJ】【1825】Free Tour 2
点分治
点分治的例题2(本题代码结果为TLE……)
强烈谴责卡时限QAQ,T了无数次啊无数次……
不过在N次的静态查错中倒是加深了对点分治的理解……也算因祸得福吧(自我安慰一下)
TLE后的改进:每棵子树在重算f数组的时候,不要完全清空,而是清到最深深度即可。——>WA
1 //SPOJ 1825 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<iostream> 6 #include<algorithm> 7 #define rep(i,n) for(int i=0;i<n;++i) 8 #define F(i,j,n) for(int i=j;i<=n;++i) 9 #define D(i,j,n) for(int i=j;i>=n;--i) 10 using namespace std; 11 inline void read(int &v){ 12 v=0; int sign=1; char ch=getchar(); 13 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 14 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 15 v*=sign; 16 } 17 /******************tamplate*********************/ 18 const int N=200010,INF=1e8; 19 int n,m,k,root=0,h[N],s[N],g[N],f[N],size,d[N]; 20 bool vis[N],black[N]; 21 int to[N],head[N],next[N],len[N],tot=0; 22 inline void ins(int x,int y,int l){ 23 to[++tot]=y; next[tot]=head[x]; head[x]=tot; len[tot]=l; 24 to[++tot]=x; next[tot]=head[y]; head[y]=tot; len[tot]=l; 25 } 26 27 inline void getroot(int x,int fa){ 28 s[x]=1;h[x]=0; 29 for(int i=head[x];i;i=next[i]) 30 if (to[i]!=fa && !vis[to[i]]){ 31 getroot(to[i],x); 32 s[x]+=s[to[i]]; 33 //h[x]=max(h[x],s[to[i]]); 34 if (s[to[i]]>h[x]) h[x]=s[to[i]]; 35 } 36 h[x]=max(h[x],size-s[x]); 37 if (h[x]<h[root]) root=x; 38 } 39 40 inline void getdep(int x,int fa){ 41 int res=0; 42 for(int i=head[x];i;i=next[i]){ 43 if (to[i]!=fa && !vis[to[i]]){ 44 d[to[i]]=d[x]+black[to[i]]; 45 getdep(to[i],x); 46 res=max(res,d[to[i]]); 47 } 48 } 49 d[x]+=res; 50 } 51 inline void getg(int x,int fa,int leng,int c){ 52 g[c]=max(g[c],leng); 53 for(int i=head[x];i;i=next[i]) 54 if (to[i]!=fa && !vis[to[i]]) getg(to[i],x,leng+len[i],c+black[to[i]]); 55 } 56 struct node{int deep,to,len;}st[N]; 57 inline bool cmp(const node &a,const node &b) {return a.deep<b.deep;} 58 int ans=0,cnt; 59 60 void getans(int x){ 61 vis[x]=1; 62 for(int i=head[x];i;i=next[i]) 63 getdep(to[i],x); 64 cnt=0; 65 F(i,0,n) f[i]=0; 66 for(int i=head[x];i;i=next[i]){ 67 if (!vis[to[i]]){ 68 d[to[i]]=black[to[i]]; 69 getdep(to[i],x); 70 st[cnt++]=(node){d[to[i]],to[i],len[i]}; 71 } 72 } 73 sort(st,st+cnt,cmp); 74 rep(i,cnt){ 75 int y=st[i].to; 76 F(j,0,d[y]) g[j]=-INF; 77 getg(y,x,st[i].len,black[y]); 78 if (i>0){ 79 int end=min(k-black[x],d[y]); 80 F(j,0,end){ 81 int p=min(d[st[i-1].to],k-j-black[x]); 82 if (f[p]==-INF) break; 83 if (g[j]!=-INF) ans=max(ans,g[j]+f[p]); 84 } 85 } 86 F(j,0,d[y]){ 87 f[j]=max(f[j],g[j]); 88 if (j) f[j]=max(f[j],f[j-1]); 89 if (j+black[x]<=k) ans=max(ans,f[j]); 90 } 91 } 92 93 for(int i=head[x];i;i=next[i]) 94 if (!vis[to[i]]){ 95 root=0; size=s[to[i]]; 96 getroot(to[i],x); 97 getans(root); 98 } 99 } 100 101 int main(){ 102 // freopen("1825.in","r",stdin); 103 read(n); read(k); read(m); 104 int x,y,l; 105 F(i,1,m){ read(x); black[x]|=1;} 106 F(i,2,n){ 107 read(x); read(y); read(l); 108 ins(x,y,l); 109 } 110 root=0; size=n; h[root]=INF; 111 getroot(1,0); 112 getans(root); 113 printf("%d\n",ans); 114 return 0; 115 }
WA:deep要反过来求,d[x]表示以x为根的子树中黑点最长的路径(而不是从root到x经过了多少黑点)
虽然好像原来的求法也能做不过不如这个方便(我一开始是写成两种混合了……QAQ)
RE:数组不能开20W,我改了个40W过了QAQ【iwtwiioi:双向边当然要开两倍的边集】!!!
1 //SPOJ 1825 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<iostream> 6 #include<algorithm> 7 #define rep(i,n) for(int i=0;i<n;++i) 8 #define F(i,j,n) for(int i=j;i<=n;++i) 9 #define D(i,j,n) for(int i=j;i>=n;--i) 10 using namespace std; 11 inline void read(int &v){ 12 v=0; int sign=1; char ch=getchar(); 13 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 14 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 15 v*=sign; 16 } 17 /******************tamplate*********************/ 18 const int N=400010,INF=1e8; 19 int n,m,k,root=0,h[N],s[N],g[N],f[N],size,d[N]; 20 bool vis[N],black[N]; 21 int to[N],head[N],next[N],len[N],tot=0; 22 inline void ins(int x,int y,int l){ 23 to[++tot]=y; next[tot]=head[x]; head[x]=tot; len[tot]=l; 24 to[++tot]=x; next[tot]=head[y]; head[y]=tot; len[tot]=l; 25 } 26 27 inline void getroot(int x,int fa){ 28 s[x]=1;h[x]=0; 29 for(int i=head[x];i;i=next[i]) 30 if (to[i]!=fa && !vis[to[i]]){ 31 getroot(to[i],x); 32 s[x]+=s[to[i]]; 33 //h[x]=max(h[x],s[to[i]]); 34 if (s[to[i]]>h[x]) h[x]=s[to[i]]; 35 } 36 h[x]=max(h[x],size-s[x]); 37 if (h[x]<h[root]) root=x; 38 } 39 40 inline void getdep(int x,int fa){ 41 int res=0; 42 s[x]=1; d[x]=black[x]; 43 for(int i=head[x];i;i=next[i]){ 44 if (to[i]!=fa && !vis[to[i]]){ 45 getdep(to[i],x); 46 res=max(res,d[to[i]]); 47 s[x]+=s[to[i]]; 48 } 49 } 50 d[x]+=res;//x为根的子树的最大“深度” 51 } 52 inline void getg(int x,int fa,int leng,int c){ 53 g[c]=max(g[c],leng); 54 for(int i=head[x];i;i=next[i]) 55 if (to[i]!=fa && !vis[to[i]]) 56 getg(to[i],x,leng+len[i],c+black[to[i]]); 57 } 58 59 inline bool cmp(int x,int y){ 60 return d[to[x]]<d[to[y]]; 61 } 62 int ans=0,st[N],cnt; 63 64 inline void getans(int x){ 65 vis[x]=1;//vis=1保证递归搜索子树时不会搜到当前节点 66 //对根的出边按dep排序 67 cnt=0; 68 for(int i=head[x];i;i=next[i]){ 69 if (!vis[to[i]]){ 70 getdep(to[i],x); 71 st[cnt++]=i; 72 } 73 } 74 sort(st,st+cnt,cmp); 75 F(i,0,d[to[st[cnt-1]]]) f[i]=-INF; 76 rep(i,cnt){ 77 int y=to[st[i]]; 78 F(j,0,d[y]) g[j]=-INF; 79 getg(y,x,len[st[i]],black[y]); 80 if (i>0){ 81 int end=min(k-black[x],d[y]); 82 F(j,0,end){ 83 int p=min(d[to[st[i-1]]],k-j-black[x]); 84 if (f[p]==-INF) break;//!!!这里没懂 85 if (g[j]!=-INF) ans=max(ans,g[j]+f[p]); 86 } 87 } 88 F(j,0,d[y]){ 89 f[j]=max(f[j],g[j]); 90 if (j) f[j]=max(f[j],f[j-1]); 91 if (j+black[x]<=k) ans=max(ans,f[j]); 92 } 93 } 94 95 for(int i=head[x];i;i=next[i]) 96 if (!vis[to[i]]){ 97 root=0; size=s[to[i]]; 98 getroot(to[i],x); 99 getans(root); 100 } 101 } 102 103 int main(){ 104 #ifndef ONLINE_JUDGE 105 freopen("1825.in","r",stdin); 106 #endif 107 read(n); read(k); read(m); 108 int x,y,l; 109 F(i,1,m){ read(x); black[x]|=1;} 110 F(i,2,n){ 111 read(x); read(y); read(l); 112 ins(x,y,l); 113 } 114 root=0; size=n; h[root]=INF; 115 getroot(1,0); 116 getans(root); 117 printf("%d\n",ans); 118 return 0; 119 }
调了一天半终于出来了!锻炼了耐心和静态查错能力~