[BZOJ2870]最长道路tree:点分治
算法一:点分治+线段树
分析
说是线段树,但是其实要写树状数组卡常。
代码
#include <bits/stdc++.h>
#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
#define lowbit(x) ((x)&(-(x)))
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=50005;
int n,ecnt,cog,totsiz,maxv,now,top,head[MAXN],siz[MAXN],sta[MAXN];
int loc,ql,qr,val[MAXN],maxn[66005],tag[66005],kk;
LL ans;
bool vis[MAXN];
struct Edge{
int to,nxt;
}e[MAXN<<1];
inline void add_edge(int bg,int ed){
++ecnt;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
}
//#define mid ((l+r)>>1)
//#define lc (o<<1)
//#define rc ((o<<1)|1)
//
//inline void pushdown(int o){
// if(!tag[o]) return;
// maxn[lc]=maxn[rc]=0;
// tag[lc]=tag[rc]=true;
// tag[o]=false;
//}
//
//void upd(int o,int l,int r){
// if(l==r){
// maxn[o]=std::max(maxn[o],kk);
// return;
// }
// pushdown(o);
// if(loc<=mid) upd(lc,l,mid);
// else upd(rc,mid+1,r);
// maxn[o]=std::max(maxn[lc],maxn[rc]);
//}
//
//int query(int o,int l,int r){
// if(ql<=l&&r<=qr) return maxn[o];
// pushdown(o);
// LL ret=0;
// if(mid>=ql) ret=std::max(ret,query(lc,l,mid));
// if(mid<qr) ret=std::max(ret,query(rc,mid+1,r));
// return ret;
//}
//
//#undef mid
//#undef lc
//#undef rc
void upd(int x,int k){
for(register int i=x;i<=maxv+1;i+=lowbit(i)){
if(tag[i]==now) maxn[i]=std::max(maxn[i],k);
else maxn[i]=k,tag[i]=now;
}
}
void upd(int o,int l,int r){
upd(maxv-loc+1,kk);
}
int query(int x){
int ret=0;
for(register int i=x;i;i-=lowbit(i)) if(tag[i]==now) ret=std::max(ret,maxn[i]);
return ret;
}
int query(int o,int l,int r){
return query(maxv-ql+1);
}
void dfs1(int x,int pre,int len,int minv){
siz[x]=1;
ql=minv,qr=maxv,ans=std::max(ans,1ll*(len+query(1,0,maxv)-1)*minv);
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
dfs1(ver,x,len+1,std::min(minv,val[ver]));
siz[x]+=siz[ver];
}
}
void dfs2(int x,int pre,int len,int minv){
loc=minv,kk=len,upd(1,0,maxv);
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
dfs2(ver,x,len+1,std::min(minv,val[ver]));
}
}
void getcog(int x,int pre){
siz[x]=1;bool flag=true;
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
getcog(ver,x);
siz[x]+=siz[ver];
if(siz[ver]>totsiz/2) flag=false;
}
if(totsiz-siz[x]>totsiz/2) flag=false;
if(flag) cog=x;
}
void solve(int x){
vis[x]=true;top=0;
ans=std::max(ans,1ll*val[x]);
++now;
loc=val[x],kk=1,upd(1,0,maxv);
trav(i,x){
int ver=e[i].to;
if(vis[ver]) continue;
sta[++top]=ver;
dfs1(ver,x,2,std::min(val[x],val[ver]));
dfs2(ver,x,2,std::min(val[x],val[ver]));
}
// maxn[1]=0,tag[1]=true;
++now;
loc=val[x],kk=1,upd(1,0,maxv);
while(top){
int ver=sta[top];
dfs1(ver,x,2,std::min(val[x],val[ver]));
dfs2(ver,x,2,std::min(val[x],val[ver]));
top--;
}
// maxn[1]=0,tag[1]=true;
trav(i,x){
int ver=e[i].to;
if(vis[ver]) continue;
totsiz=siz[ver];
getcog(ver,x);
solve(cog);
}
}
int main(){
n=read();
rin(i,1,n) val[i]=read(),maxv=std::max(maxv,val[i]);
rin(i,2,n){
int u=read(),v=read();
add_edge(u,v);
add_edge(v,u);
}
totsiz=n;
getcog(1,0);
solve(cog);
printf("%lld\n",ans);
return 0;
}
算法二:点分治
分析
边分治转点分治(不用学边分治了)(大雾)。
代码
#include <bits/stdc++.h>
#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=50005;
int n,ecnt,cog,totsiz,now,head[MAXN],val[MAXN],siz[MAXN],vis[MAXN];
int len1,len2;LL ans;
struct Edge{
int to,nxt;
}e[MAXN<<1];
struct info{
int dis,minv;
inline friend bool operator < (info x,info y){
return x.minv==y.minv?x.dis<y.dis:x.minv>y.minv;
}
}arr1[MAXN],arr2[MAXN];
inline void add_edge(int bg,int ed){
++ecnt;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
}
void getcog(int x,int pre){
siz[x]=1;bool flag=true;
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
getcog(ver,x);
siz[x]+=siz[ver];
if(siz[ver]>totsiz/2) flag=false;
}
if(totsiz-siz[x]>totsiz/2) flag=false;
if(flag) cog=x;
}
void dfs(int x,int pre,int dis,int minv,info *arr,int &len){
arr[++len]=(info){dis,minv};
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
dfs(ver,x,dis+1,std::min(minv,val[ver]),arr,len);
}
}
void solve(int x){
getcog(x,0);
if(totsiz==2){
int y=0;
trav(i,x){
int ver=e[i].to;
if(vis[ver]) continue;
y=ver;break;
}
ans=std::max(std::max(ans,std::min(val[x],val[y])*2ll)
,std::max(1ll*val[x],1ll*val[y]));
return;
}
int one=0,thisnow=++now;
trav(i,x){
int ver=e[i].to;
if(vis[ver]) continue;
if(one+siz[ver]>totsiz/2) vis[ver]=now;
else one+=siz[ver];
}
int ano=totsiz-one;++one,len1=len2=0;
dfs(x,0,1,val[x],arr1,len1);
trav(i,x){
int ver=e[i].to;
if(vis[ver]&&vis[ver]!=thisnow) continue;
vis[ver]^=thisnow;
}
dfs(x,0,1,val[x],arr2,len2);
std::sort(arr1+1,arr1+len1+1);
std::sort(arr2+1,arr2+len2+1);
int ptr=0,premax=-1;
rin(i,1,len1){
while(ptr<len2&&arr2[ptr+1].minv>=arr1[i].minv) premax=std::max(premax,arr2[++ptr].dis);
ans=std::max(ans,1ll*(arr1[i].dis+premax-1)*arr1[i].minv);
}
ptr=0,premax=-1;
rin(i,1,len2){
while(ptr<len1&&arr1[ptr+1].minv>=arr2[i].minv) premax=std::max(premax,arr1[++ptr].dis);
ans=std::max(ans,1ll*(arr2[i].dis+premax-1)*arr2[i].minv);
}
totsiz=ano;
getcog(x,0);
solve(cog);
vis[x]=0;
trav(i,x){
int ver=e[i].to;
if(vis[ver]&&vis[ver]!=thisnow) continue;
vis[ver]^=thisnow;
}
totsiz=one;
getcog(x,0);
solve(cog);
}
int main(){
n=read();
rin(i,1,n) val[i]=read();
rin(i,2,n){
int u=read(),v=read();
add_edge(u,v);
add_edge(v,u);
}
totsiz=n;
getcog(1,0);
solve(cog);
printf("%lld\n",ans);
}
[BZOJ2870]最长道路tree:点分治的更多相关文章
- bzoj2870最长道路tree——边分治
简化版描述: 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数. 有几个不同的做法: 1.sort+并查集+树的直径.边从大到小加入 ...
- 【BZOJ2870】最长道路tree 点分治+树状数组
[BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来 ...
- BZOJ2870—最长道路tree
最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来往,所以每个路口i都 ...
- BZOJ2870: 最长道路tree
题解: 子树分治的做法可以戳这里:http://blog.csdn.net/iamzky/article/details/41120733 可是码量... 这里介绍另一种好写又快的方法. 我们还是一颗 ...
- bzoj 2870 最长道路tree——边分治
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2870 关于边分治:https://www.cnblogs.com/Khada-Jhin/p/ ...
- BZOJ2870 最长道路tree(并查集+LCA)
题意 (n<=50000) 题解 #include<iostream> #include<cstring> #include<cstdio> #include ...
- 【BZOJ2870】最长道路(边分治)
[BZOJ2870]最长道路(边分治) 题面 BZOJ权限题 Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样 ...
- 【bzoj2870】最长道路tree 树的直径+并查集
题目描述 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数. 输入 第一行N 第二行N个数分别表示1~N的点权v[i] 接下来N-1行每 ...
- BZOJ2870 最长道路
题意:给定树,有点权.求一条路径使得最小点权 * 总点数最大.只需输出这个最大值.5w. 解:树上路径问题,点分治. 考虑合并两个子树的时候,答案的形式是val1 * (d1 + d2),当1是新插入 ...
随机推荐
- Solr 4.4.0利用dataimporthandler导入postgresql数据库表
将数据库edbstore的edbtore schema下的customers表导入到solr 1. 首先查看customers表字段信息 edbstore=> \d customers Tabl ...
- 【转帖】Spring Boot 为什么这么火?
Spring Boot 为什么这么火? 2019/06/03 http://www.ityouknow.com/springboot/2019/06/03/spring-boot-hot.html 没 ...
- 拉勾网python开发要求爬虫
#今日目标 **拉勾网python开发要求爬虫** 今天要爬取的是北京python开发的薪资水平,招聘要求,福利待遇以及公司的地理位置. 通过实践发现除了必须携带headers之外,拉勾网对ip访问频 ...
- Callable+ThreadPoolExecutor实现多线程并发并获得返回值(转)
出处:https://blog.csdn.net/kity9420/article/details/80740466 前言 经常会遇到一些性能问题,比如调用某个接口,可能要循环调用100次,并且需要拿 ...
- 深入理解let和var的区别
首先我们应该知道js引擎在读取js代码时会进行两个步骤: 第一个步骤是解释. 第二个步骤是执行. 所谓解释就是会先通篇扫描所有的Js代码,然后把所有声明提升到顶端,第二步是执行,执行就是操作一类的. ...
- Longest Subsequence CodeForces - 632D (lcm)
大意: 给定序列$a$, 求选出最长的一个子序列, 使得lcm不超过m. 刚开始想复杂了, 想着枚举gcd然后背包, 这样复杂度就是$O(\sum\limits_{i=1}^m \frac{m\sig ...
- postgresql 相关操作
1.root 用户,执行 service postgresql restart service postgresql start --启动 2.查看数据库状态 /etc/init.d/postgre ...
- centos部署LVS负载均衡直接路由DR模式
环境: 在vm里开三个虚拟机 负载调度器:10.0.3.102 真实服务器1:10.0.3.103 真实服务器2:10.0.3.104 虚拟ip: 10.0.3.99 (用来飘移) 负载调度器上 if ...
- notes-19-05-10
一 mysql查找一个表中字段相同的数据 2019-05-10 15:51:03 多字段 ) 二 Referer的作用?2019-05-17 10:03:48 (来自网络) 1.防盗链我在www ...
- 从分析攻击方式来谈如何防御DDoS攻击
DDoS攻击的定义: DDoS攻击全称——分布式拒绝服务攻击,是网络攻击中非常常见的攻击方式.在进行攻击的时候,这种方式可以对不同地点的大量计算机进行攻击,进行攻击的时候主要是对攻击的目标发送超过其处 ...