题目描述





分析

  • 对于测试点\(1\)、\(2\),直接搜索即可
  • 对于测试点\(3 \sim 6\),树退化成一条链,我们可以将其看成序列上的染色问题,用线段树维护颜色相同的最长序列
  • 对于测试点\(7\)、\(8\),肯定是车的速度越大能经过的道路越少,所以我们用类似并查集的方法从大到小依次维护联通块的直径,这里要用到一个结论:如果两个点集\(A\)、\(B\)的直径分别为\((v_1,v_2)(u_1,u_2)\),那么\(A \cup B\)的直径一定出现在这\(C_4^2\)种选择之中,只要枚举每种情况更新答案就行了。
  • 对于全部的测试点,需要用到线段树分治,我们把一条边插入到线段树(下标为车速)上的\(log(n)\)个节点上,最后\(dfs\)整棵线段树,在每个节点上加入可行的边,最后的问题就是每个联通块的直径取\(max\),关于线段树分治,看这篇博客

代码

#include<cstdio>
#include<iostream>
#include<vector>
#include<stack>
#include<cstring>
#include<map>
inline int read(){
int x=0,fh=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e6+5,maxk=105;
int n,m,q[maxn],zx[maxn],son[maxn],siz[maxn],dep[maxn],head[maxn],tot=1;
struct asd{
int to,next;
}b[maxn];
void ad(int aa,int bb){
b[tot].to=bb;
b[tot].next=head[aa];
head[aa]=tot++;
}
void dfs1(int now,int fa){
siz[now]=1;
dep[now]=dep[fa]+1;
zx[now]=fa;
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(u==fa) continue;
dfs1(u,now);
siz[now]+=siz[u];
if(son[now]==0 || siz[u]>siz[son[now]]){
son[now]=u;
}
}
}
int tp[maxn],dfnc,dfn[maxn],rk[maxn];
void dfs2(int now,int top){
tp[now]=top;
dfn[now]=++dfnc;
rk[dfnc]=now;
if(son[now]) dfs2(son[now],top);
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(u==zx[now] || u==son[now]) continue;
dfs2(u,u);
}
}
int get_LCA(int u,int v){
while(tp[u]!=tp[v]){
if(dep[tp[u]]<dep[tp[v]]) std::swap(u,v);
u=zx[tp[u]];
}
if(dep[u]<dep[v]) std::swap(u,v);
return v;
}
int jsjl(int u,int v){
return dep[u]+dep[v]-2*dep[get_LCA(u,v)];
}
//log(n)求出两点之间的距离
struct trr{
int l,r;
std::vector<int> g;
}tr[maxn];
int x[maxn],y[maxn];
void build(int da,int l,int r){
tr[da].l=l,tr[da].r=r;
if(l==r){
tr[da].g.clear();
return;
}
int mids=(tr[da].l+tr[da].r)>>1;
build(da<<1,l,mids);
build(da<<1|1,mids+1,r);
}
void xg(int da,int l,int r,int val){
if(tr[da].l>=l && tr[da].r<=r){
tr[da].g.push_back(val);
return;
}
int mids=(tr[da].l+tr[da].r)>>1;
if(l<=mids) xg(da<<1,l,r,val);
if(r>mids) xg(da<<1|1,l,r,val);
}
//将边下放到线段树的节点上
struct jl{
int zb,yb,zj;
jl(){
zb=yb=zj=0;
}
}jll[maxn];
int ans[maxn],fa[maxn],d[maxn];
int zhao(int xx){
while(xx!=fa[xx]) xx=fa[xx];
return xx;
}
bool haha;
std::stack<jl> st;
std::stack<std::pair<int,int> > stt;
jl push_up(jl lc,jl rc){
jl now;
now.zj=lc.zj;
now.zb=lc.zb;
now.yb=lc.yb;
if(now.zj<rc.zj){
now.zj=rc.zj;
now.zb=rc.zb;
now.yb=rc.yb;
}
int aa=lc.zb,bb=lc.yb,cc=rc.zb,dd=rc.yb;
int ee=jsjl(aa,cc);
if(now.zj<ee){
now.zj=ee;
now.zb=aa,now.yb=cc;
}
ee=jsjl(aa,dd);
if(now.zj<ee){
now.zj=ee;
now.zb=aa,now.yb=dd;
}
ee=jsjl(bb,cc);
if(now.zj<ee){
now.zj=ee;
now.zb=bb,now.yb=cc;
}
ee=jsjl(bb,dd);
if(now.zj<ee){
now.zj=ee;
now.zb=bb,now.yb=dd;
}
return now;
}
//合并树的直径
void bing(int nx,int ny,int &len){
if(nx==1 && ny==5){
haha=1;
} else {
haha=0;
}
if(d[nx]>d[ny]) std::swap(nx,ny);
stt.push(std::make_pair(nx,d[nx]==d[ny]));
fa[nx]=ny;
d[ny]+=(d[nx]==d[ny]);
st.push(jll[ny]);
jll[ny]=push_up(jll[nx],jll[ny]);
if(len<jll[ny].zj) len=jll[ny].zj;
}
//可撤销并查集
void dfs(int da,int len){
int now=st.size();
for(int i=0;i<tr[da].g.size();i++){
int wz=tr[da].g[i];
int nx=zhao(x[wz]),ny=zhao(y[wz]);
if(nx==ny) continue;
bing(nx,ny,len);
}
if(tr[da].l==tr[da].r){
ans[tr[da].l]=len;
while(st.size()>now){
d[fa[stt.top().first]]-=stt.top().second;
jll[fa[stt.top().first]]=st.top();
fa[stt.top().first]=stt.top().first;
st.pop();
stt.pop();
}
return;
}
dfs(da<<1,len);
dfs(da<<1|1,len);
while(st.size()>now){
d[fa[stt.top().first]]-=stt.top().second;
jll[fa[stt.top().first]]=st.top();
fa[stt.top().first]=stt.top().first;
st.pop();
stt.pop();
}
}
//dfs求出答案
int main(){
memset(head,-1,sizeof(head));
n=read(),m=read();
build(1,1,n);
for(int i=1;i<=n;i++){
fa[i]=i;
jll[i].zb=jll[i].yb=i;
}
for(int i=1;i<n;i++){
int aa,bb,cc,dd;
aa=read(),bb=read(),cc=read(),dd=read();
x[i]=aa,y[i]=bb;
xg(1,cc,dd,i);
ad(aa,bb);
ad(bb,aa);
}
dfs1(1,0);
dfs2(1,1);
dfs(1,0);
for(int i=1;i<=m;i++){
q[i]=read();
printf("%d\n",ans[q[i]]);
}
return 0;
}

联赛模拟测试8 Dash Speed 线段树分治的更多相关文章

  1. 7.18 NOI模拟赛 因懒无名 线段树分治 线段树维护直径

    LINK:因懒无名 20分显然有\(n\cdot q\)的暴力. 还有20分 每次只询问一种颜色的直径不过带修改. 容易想到利用线段树维护直径就可以解决了. 当然也可以进行线段树分治 每种颜色存一下直 ...

  2. [CSP-S模拟测试]:最大值(数学+线段树)

    题目背景 $Maxtir$最喜欢最大值. 题目传送门(内部题128) 输入格式 第$1$行输入四个正整数$n,m,q$. 第$2$至$n+1$行中,第$i+1$行输入魔法晶石$i$的三种属性$(x_i ...

  3. [CSP-S模拟测试]:数对(线段树优化DP)

    题目传送门(内部题96) 输入格式 第一行一个整数$n$,接下来$n$行每行三个整数$a_i,b_i,w_i$. 输出格式 一行一个整数表示最大权值和. 样例 样例输入: 54 4 12 3 31 5 ...

  4. [CSP-S模拟测试]:模板(ac)(线段树启发式合并)

    题目描述 辣鸡$ljh\ NOI$之后就退役了,然后就滚去学文化课了.他每天都被$katarina$大神虐,仗着自己学过一些姿势就给$katarina$大神出了一道题.有一棵$n$个节点的以$1$号节 ...

  5. [CSP-S模拟测试]:甜圈(线段树)

    题目描述 $D$先生,是一个了不起的甜甜圈制造商.今天,他的厨房准备在日出之前制作甜甜圈.$D$先生瞬间完成了$N$个油炸圈饼.但是,这些油炸圈饼得先经过各种装饰任务才可以成为甜甜圈销售:填充奶油,浸 ...

  6. [CSP-S模拟测试]:God Knows(线段树维护单调栈)

    题目描述 小$w$来到天堂的门口,对着天堂的大门发呆.大门上有一个二分图,左边第$i$个点连到右边第$p_i$个点.(保证$p_i$是一个排列).小$w$每次可以找左边某个对应连线尚未被移除的点$i$ ...

  7. [CSP-S模拟测试]:旅行(数学+线段树)

    题目传送门(内部题12) 输入格式 第一行,一个整数$n$,代表树的点数.第二行,$n$个整数,第$i$个整数是$B_i$,描述排列$B$.接下来$n−1$行,每行两个整数$u,v$,描述一条树边$( ...

  8. [CSP-S模拟测试]:F(DP+线段树)

    题目传送门(内部题49) 输入格式 第一行四个整数$n,q,a,b$.接下来$n$行每行一个整数$p_i$. 输出格式 一行一个整数表示答案. 样例 样例输入: 10 3 3 7 样例输出: 数据范围 ...

  9. 洛谷 P2147 [SDOI2008]洞穴勘测 (线段树分治)

    题目链接 题解 早就想写线段树分治的题了. 对于每条边,它存在于一段时间 我们按时间来搞 我们可把一条边看做一条线段 我们可以模拟线段树操作,不断分治下去 把覆盖\(l-r\)这段时间的线段筛选出来, ...

随机推荐

  1. 企业网站SEO如何选择关键词

    http://www.wocaoseo.com/thread-17-1-1.html       企业网站的关键词应该如何去选择?有很多的企业老板在网上某某企业在网上做了一个网站,一天盈利多少后,觉得 ...

  2. 关于提高服务器的带宽策略bonding

    一:bonding的概念 所谓bonding就是将多块网卡绑定同一IP地址对外提供服务,可以实现网卡的带宽扩容.高可用或者负载均衡. 二:bonding的优势 1 网络负载均衡 2 提高带宽网络传输效 ...

  3. Python字符串类型格式化之format方法

    python字符串格式化一般使用 format() 方法,用法如下: <模板字符串>.format(<逗号分割的参数>) 其中模板字符串中可以由一个或多个 {} 组成的 槽 , ...

  4. MySQL集群搭建方案(PXC)

    服务器快过期了,清一点库存,把运维这块的知识复习下 为什么要搭MySQL集群 技术层面上,传统的单节点数据库,万一宕机了,就凉凉了.容灾性能差.抗并发能力有限,数据量大的时候查询有瓶颈.学习层面上,作 ...

  5. 基于laravel的有偿开源流程引擎

    系统主要文档已经编写完成,具体请前往查看[系统文档](https://www.kancloud.cn/lijianlin/jishullin_workflow_engine/1894424 " ...

  6. Oracle12C创建视图权限不足

    授权: GRANT CREATE VIEW TO c##scott; 作者:彼岸舞 时间:2020\06\23 内容关于:Oracle 本文属于作者原创,未经允许,禁止转发

  7. H5简单内容

    1.简单认识H5 HTML5不仅仅是作为HTML标记语言的一个最新版本,更重要的是它指定了Web开发的一系列标准,成为第一个将Web作为应用开发平台的HTML语言. 我们日常讨论的H5其实是有一个泛称 ...

  8. ctfhub sql注入 整数型注入

    整数型注入 手工注入 1.查看是否存在sql注入,及sql注入类型 2.确定列数 3.确定注入点,以及数据库版本,数据库名称 4.查表名 5.查字段名以及flag值 获得flag值 sqlmap做法 ...

  9. Oracle闪回flashback

    参考资料:Using Oracle Flashback Technology Oracle 11g的新特性闪回操作 闪回查询 闪回查询 闪回版本查询 闪回事务查询 闪回数据 闪回表 闪回删除 闪回数据 ...

  10. 复习 | 彻底弄懂Flexbox之Demo篇

    flexbox之前有接触,写项目时也用过,但也只是简单的,对其也是似懂非懂,所以今天下定决心把这个再学一遍,因为似懂非懂就是不懂 本文主要是的demo演示,想看flexbox语法 请移步flexbox ...