【SPOJ】【1825】Free Tour 2
点分治
点分治的例题2(本题代码结果为TLE……)
强烈谴责卡时限QAQ,T了无数次啊无数次……
不过在N次的静态查错中倒是加深了对点分治的理解……也算因祸得福吧(自我安慰一下)
TLE后的改进:每棵子树在重算f数组的时候,不要完全清空,而是清到最深深度即可。——>WA
//SPOJ 1825
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
using namespace std;
inline void read(int &v){
v=; int sign=; char ch=getchar();
while(ch<''||ch>''){ if (ch=='-') sign=-; ch=getchar();}
while(ch>=''&&ch<=''){ v=v*+ch-''; ch=getchar();}
v*=sign;
}
/******************tamplate*********************/
const int N=,INF=1e8;
int n,m,k,root=,h[N],s[N],g[N],f[N],size,d[N];
bool vis[N],black[N];
int to[N],head[N],next[N],len[N],tot=;
inline void ins(int x,int y,int l){
to[++tot]=y; next[tot]=head[x]; head[x]=tot; len[tot]=l;
to[++tot]=x; next[tot]=head[y]; head[y]=tot; len[tot]=l;
} inline void getroot(int x,int fa){
s[x]=;h[x]=;
for(int i=head[x];i;i=next[i])
if (to[i]!=fa && !vis[to[i]]){
getroot(to[i],x);
s[x]+=s[to[i]];
//h[x]=max(h[x],s[to[i]]);
if (s[to[i]]>h[x]) h[x]=s[to[i]];
}
h[x]=max(h[x],size-s[x]);
if (h[x]<h[root]) root=x;
} inline void getdep(int x,int fa){
int res=;
for(int i=head[x];i;i=next[i]){
if (to[i]!=fa && !vis[to[i]]){
d[to[i]]=d[x]+black[to[i]];
getdep(to[i],x);
res=max(res,d[to[i]]);
}
}
d[x]+=res;
}
inline void getg(int x,int fa,int leng,int c){
g[c]=max(g[c],leng);
for(int i=head[x];i;i=next[i])
if (to[i]!=fa && !vis[to[i]]) getg(to[i],x,leng+len[i],c+black[to[i]]);
}
struct node{int deep,to,len;}st[N];
inline bool cmp(const node &a,const node &b) {return a.deep<b.deep;}
int ans=,cnt; void getans(int x){
vis[x]=;
for(int i=head[x];i;i=next[i])
getdep(to[i],x);
cnt=;
F(i,,n) f[i]=;
for(int i=head[x];i;i=next[i]){
if (!vis[to[i]]){
d[to[i]]=black[to[i]];
getdep(to[i],x);
st[cnt++]=(node){d[to[i]],to[i],len[i]};
}
}
sort(st,st+cnt,cmp);
rep(i,cnt){
int y=st[i].to;
F(j,,d[y]) g[j]=-INF;
getg(y,x,st[i].len,black[y]);
if (i>){
int end=min(k-black[x],d[y]);
F(j,,end){
int p=min(d[st[i-].to],k-j-black[x]);
if (f[p]==-INF) break;
if (g[j]!=-INF) ans=max(ans,g[j]+f[p]);
}
}
F(j,,d[y]){
f[j]=max(f[j],g[j]);
if (j) f[j]=max(f[j],f[j-]);
if (j+black[x]<=k) ans=max(ans,f[j]);
}
} for(int i=head[x];i;i=next[i])
if (!vis[to[i]]){
root=; size=s[to[i]];
getroot(to[i],x);
getans(root);
}
} int main(){
// freopen("1825.in","r",stdin);
read(n); read(k); read(m);
int x,y,l;
F(i,,m){ read(x); black[x]|=;}
F(i,,n){
read(x); read(y); read(l);
ins(x,y,l);
}
root=; size=n; h[root]=INF;
getroot(,);
getans(root);
printf("%d\n",ans);
return ;
}
WA:deep要反过来求,d[x]表示以x为根的子树中黑点最长的路径(而不是从root到x经过了多少黑点)
虽然好像原来的求法也能做不过不如这个方便(我一开始是写成两种混合了……QAQ)
RE:数组不能开20W,我改了个40W过了QAQ【iwtwiioi:双向边当然要开两倍的边集】!!!
//SPOJ 1825
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
using namespace std;
inline void read(int &v){
v=; int sign=; char ch=getchar();
while(ch<''||ch>''){ if (ch=='-') sign=-; ch=getchar();}
while(ch>=''&&ch<=''){ v=v*+ch-''; ch=getchar();}
v*=sign;
}
/******************tamplate*********************/
const int N=,INF=1e8;
int n,m,k,root=,h[N],s[N],g[N],f[N],size,d[N];
bool vis[N],black[N];
int to[N],head[N],next[N],len[N],tot=;
inline void ins(int x,int y,int l){
to[++tot]=y; next[tot]=head[x]; head[x]=tot; len[tot]=l;
to[++tot]=x; next[tot]=head[y]; head[y]=tot; len[tot]=l;
} inline void getroot(int x,int fa){
s[x]=;h[x]=;
for(int i=head[x];i;i=next[i])
if (to[i]!=fa && !vis[to[i]]){
getroot(to[i],x);
s[x]+=s[to[i]];
//h[x]=max(h[x],s[to[i]]);
if (s[to[i]]>h[x]) h[x]=s[to[i]];
}
h[x]=max(h[x],size-s[x]);
if (h[x]<h[root]) root=x;
} inline void getdep(int x,int fa){
int res=;
s[x]=; d[x]=black[x];
for(int i=head[x];i;i=next[i]){
if (to[i]!=fa && !vis[to[i]]){
getdep(to[i],x);
res=max(res,d[to[i]]);
s[x]+=s[to[i]];
}
}
d[x]+=res;//x为根的子树的最大“深度”
}
inline void getg(int x,int fa,int leng,int c){
g[c]=max(g[c],leng);
for(int i=head[x];i;i=next[i])
if (to[i]!=fa && !vis[to[i]])
getg(to[i],x,leng+len[i],c+black[to[i]]);
} inline bool cmp(int x,int y){
return d[to[x]]<d[to[y]];
}
int ans=,st[N],cnt; inline void getans(int x){
vis[x]=;//vis=1保证递归搜索子树时不会搜到当前节点
//对根的出边按dep排序
cnt=;
for(int i=head[x];i;i=next[i]){
if (!vis[to[i]]){
getdep(to[i],x);
st[cnt++]=i;
}
}
sort(st,st+cnt,cmp);
F(i,,d[to[st[cnt-]]]) f[i]=-INF;
rep(i,cnt){
int y=to[st[i]];
F(j,,d[y]) g[j]=-INF;
getg(y,x,len[st[i]],black[y]);
if (i>){
int end=min(k-black[x],d[y]);
F(j,,end){
int p=min(d[to[st[i-]]],k-j-black[x]);
if (f[p]==-INF) break;//!!!这里没懂
if (g[j]!=-INF) ans=max(ans,g[j]+f[p]);
}
}
F(j,,d[y]){
f[j]=max(f[j],g[j]);
if (j) f[j]=max(f[j],f[j-]);
if (j+black[x]<=k) ans=max(ans,f[j]);
}
} for(int i=head[x];i;i=next[i])
if (!vis[to[i]]){
root=; size=s[to[i]];
getroot(to[i],x);
getans(root);
}
} int main(){
#ifndef ONLINE_JUDGE
freopen("1825.in","r",stdin);
#endif
read(n); read(k); read(m);
int x,y,l;
F(i,,m){ read(x); black[x]|=;}
F(i,,n){
read(x); read(y); read(l);
ins(x,y,l);
}
root=; size=n; h[root]=INF;
getroot(,);
getans(root);
printf("%d\n",ans);
return ;
}
调了一天半终于出来了!锻炼了耐心和静态查错能力~
【SPOJ】【1825】Free Tour 2的更多相关文章
- 【SPOJ】1825. Free tour II(点分治)
http://www.spoj.com/problems/FTOUR2/ 先前看了一会题解就自己yy出来了...对拍过后交tle.................. 自己造了下大数据........t ...
- 【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)
54 种草约翰有 N 个牧场,编号为 1 到 N.它们之间有 N − 1 条道路,每条道路连接两个牧场.通过这些道路,所有牧场都是连通的.刚开始的时候,所有道路都是光秃秃的,没有青草.约翰会在一些道 ...
- 【SPOJ】NUMOFPAL - Number of Palindromes(Manacher,回文树)
[SPOJ]NUMOFPAL - Number of Palindromes(Manacher,回文树) 题面 洛谷 求一个串中包含几个回文串 题解 Manacher傻逼题 只是用回文树写写而已.. ...
- 【SPOJ】Substrings(后缀自动机)
[SPOJ]Substrings(后缀自动机) 题面 Vjudge 题意:给定一个长度为\(len\)的串,求出长度为1~len的子串中,出现最多的出现了多少次 题解 出现次数很好处理,就是\(rig ...
- 【SPOJ】Longest Common Substring II (后缀自动机)
[SPOJ]Longest Common Substring II (后缀自动机) 题面 Vjudge 题意:求若干个串的最长公共子串 题解 对于某一个串构建\(SAM\) 每个串依次进行匹配 同时记 ...
- 【SPOJ】Longest Common Substring(后缀自动机)
[SPOJ]Longest Common Substring(后缀自动机) 题面 Vjudge 题意:求两个串的最长公共子串 题解 \(SA\)的做法很简单 不再赘述 对于一个串构建\(SAM\) 另 ...
- 【SPOJ】Distinct Substrings(后缀自动机)
[SPOJ]Distinct Substrings(后缀自动机) 题面 Vjudge 题意:求一个串的不同子串的数量 题解 对于这个串构建后缀自动机之后 我们知道每个串出现的次数就是\(right/e ...
- 【SPOJ】Distinct Substrings/New Distinct Substrings(后缀数组)
[SPOJ]Distinct Substrings/New Distinct Substrings(后缀数组) 题面 Vjudge1 Vjudge2 题解 要求的是串的不同的子串个数 两道一模一样的题 ...
- 【SPOJ】Power Modulo Inverted(拓展BSGS)
[SPOJ]Power Modulo Inverted(拓展BSGS) 题面 洛谷 求最小的\(y\) 满足 \[k\equiv x^y(mod\ z)\] 题解 拓展\(BSGS\)模板题 #inc ...
- 【SPOJ】QTREE7(Link-Cut Tree)
[SPOJ]QTREE7(Link-Cut Tree) 题面 洛谷 Vjudge 题解 和QTREE6的本质是一样的:维护同色联通块 那么,QTREE6同理,对于两种颜色分别维护一棵\(LCT\) 每 ...
随机推荐
- Netty 实现SSL安全连接(wss://)
原文:Netty5使用自签证书实现SSL安全连接 在客户端是https:// 协议下,使用ws:// 协议连接会报错的,得需要使用wss:// 连接.(ip连接失败时使用域名连接) netty创建服务 ...
- Mysql安装(绿色版安装)
一:下载 1.官网 https://dev.mysql.com/ 2.下载 3.下载 二:安装 1.将官网上下载的包进行解压 2.以管理员的身份运行DOS安装 进入mysql的bin目录 运行mysq ...
- poj2524 Ubiquitous Religions(并查集)
题目链接 http://poj.org/problem?id=2524 题意 有n个学生,编号1~n,每个学生最多有1个宗教信仰,输入m组数据,每组数据包含a.b,表示同学a和同学b有相同的信仰,求在 ...
- ASP.NET MVC 提高运行速度的几种性能优化方法
主要介绍ASP.NETMVC 应用提速的六种方法,因为没有人喜欢等待,所以介绍几种常用的优化方法. 大家可能会遇到排队等待,遇到红灯要等待,开个网页要等待,等等等. 理所当然,没有人喜欢等待网页慢吞吞 ...
- JAVA内存泄漏解决办法
JVM调优工具 Jconsole,jProfile,VisualVM Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用.对垃圾回收算法有很详细的跟踪.详细说明参考这里 ...
- 列表中字符串按照某种规则排序的方法(python)
有时候处理数据时,想要按照字符串中的数字的大小进行排序. 譬如,存在一组记录文件,分别为‘1.dat’,'2.dat'... 当我把该文件夹中的所有记录文件名读到一个列表中,这些字符串的排列方式为: ...
- 01-学前入门.Net两种交换模式
C/S:客户机(Client)/服务器模式(Server)Winfrom应用程序 B/S:浏览器(Browser)/服务器模式(Server)Internet应用模式
- 洛谷.4512.[模板]多项式除法(NTT)
题目链接 多项式除法 & 取模 很神奇,记录一下. 只是主要部分,更详细的和其它内容看这吧. 给定一个\(n\)次多项式\(A(x)\)和\(m\)次多项式\(D(x)\),求\(deg(Q) ...
- [UOJ422]小Z的礼物
设要取的物品集合为$S$,$E=n(m-1)+(n-1)m$,$x_T$为覆盖了$T$中至少一个元素的$1\times2$数量 $$\begin{aligned}\sum\limits_{i=1}^\ ...
- bzoj 1658: [Usaco2006 Mar]Water Slides 滑水
题解: 很神奇的做法,把点分成入度大于出度和入度小于出度两种. 然后入度大于出度的点必须走到某个点,所以排序贪心. #include<stdio.h> #include<iostre ...