BZOJ 1906. 树上的蚂蚁
发现蚂蚁不多,所以考虑两两枚举然后判断
那么首先要求出两条链的公共部分,然后根据之间在公共链的时间段和是同向还是反向进行判断
思路简单但是细节很多......
首先求链的公共部分,设两种蚂蚁为 $a,b$,路径分别为 $As,At$,$Bs,Bt$
那么经过一波手玩分类讨论,公共部分的两端点就是 $LCA(As,Bs),LCA(As,Bt),LCA(At,Bs),LCA(At,Bt)$ 之间 $dfs$ 序较大的两个
记得之前要先把不在两条链上的点去掉,然后如果最后只有一个点合法则公共部分只有一个点
然后每只蚂蚁在公共链的起点就是距离比较近的那个,判断是否同向只要看看公共链起点是否相等即可
判断点是否在某条链上,因为边权不为 $0$ ,所以可以用点到链两端点的距离和是否等于链长来判断
然后如果两只蚂蚁同向,那么只要判断先到达公共链起点的后到达公共链终点即可
如果不同向,那么要判断它们在公共链的时间区间是否有交
为了避免除法所以移项变成乘法,注意乘会爆 $int$
因为多次求 $LCA$,所以要 $RMQ$ $O(1)$ 求 $LCA$
具体实现我感觉自己代码还挺好看的...
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=2e5+,INF=1e9+;
int n,m,S[N],T[N],V[N],Ans;
int fir[N],from[N<<],to[N<<],val[N<<],cntt;
inline void add(int a,int b,int c)
{
from[++cntt]=fir[a]; fir[a]=cntt;
to[cntt]=b; val[cntt]=c;
}
int dep[N],dfn[N],cnt,st[N<<],pos[N<<],Top;
void dfs(int x,int fa)
{
dfn[x]=++cnt; st[++Top]=x; pos[x]=Top;
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(v==fa) continue;
dep[v]=dep[x]+val[i]; dfs(v,x); st[++Top]=x;
}
}
int F[N<<][],Log[N<<];
void pre()
{
Log[]=-; for(int i=;i<=Top;i++) Log[i]=Log[i>>]+;//
for(int i=;i<=Top;i++) F[i][]=st[i];
for(int i=;(<<i)<=Top;i++)
for(int j=;j+(<<i-)<=Top;j++)
{
if( dfn[F[j][i-]] < dfn[ F[j+(<<i-)][i-] ] ) F[j][i]=F[j][i-];
else F[j][i]=F[j+(<<i-)][i-];
}
}
inline int query(int x,int y)
{
int l=pos[x],r=pos[y],k; if(l>r) swap(l,r);
k=Log[r-l+];
if(dfn[F[l][k]]<dfn[F[r-(<<k)+][k]]) return F[l][k];
else return F[r-(<<k)+][k];
}
inline ll dis(int x,int y) { return dep[x]+dep[y]-*dep[query(x,y)]; }
inline bool cmp(const int &A,const int &B) { return dfn[A]>dfn[B]; }
inline bool in_chain(int x,int y,int a) { return dis(x,a)+dis(y,a)==dis(x,y); }
inline bool pd(ll l,ll r,ll x) { return x>=l && x<=r; }
inline bool solve(int As,int At,int Bs,int Bt,int Av,int Bv)
{
int x[],tot=,p=query(As,Bs);
if(in_chain(As,At,p)&&in_chain(Bs,Bt,p)) x[++tot]=p;
p=query(As,Bt);
if(in_chain(As,At,p)&&in_chain(Bs,Bt,p)) x[++tot]=p;
p=query(At,Bs);
if(in_chain(As,At,p)&&in_chain(Bs,Bt,p)) x[++tot]=p;
p=query(At,Bt);
if(in_chain(As,At,p)&&in_chain(Bs,Bt,p)) x[++tot]=p;
if(!tot) return ;
sort(x+,x+tot+,cmp); if(tot==) x[]=x[];
int Al=(dis(As,x[])<dis(As,x[]) ? x[] : x[]),Ar=(Al==x[] ? x[] : x[]);
int Bl=(dis(Bs,x[])<dis(Bs,x[]) ? x[] : x[]),Br=(Bl==x[] ? x[] : x[]);
ll Asl=dis(As,Al)*Bv,Bsl=dis(Bs,Bl)*Av,Asr=dis(As,Ar)*Bv,Bsr=dis(Bs,Br)*Av;
if(Al==Bl)
{
if(Asl<=Bsl && Asr>=Bsr) return ;
if(Asl>=Bsl && Asr<=Bsr) return ;
return ;
}
if(pd(Asl,Asr,Bsl)||pd(Asl,Asr,Bsr)) return ;
if(pd(Bsl,Bsr,Asl)||pd(Bsl,Bsr,Asr)) return ;
return ;
}
int main()
{
int TT=read();
while(TT--)
{
cntt=Top=cnt=Ans=; for(int i=;i<=n;i++) fir[i]=;
n=read(); int a,b,c;
for(int i=;i<n;i++)
{
a=read(),b=read(),c=read();
add(a,b,c); add(b,a,c);
}
m=read();
for(int i=;i<=m;i++) S[i]=read(),T[i]=read(),V[i]=read();
dfs(,); pre();
for(int i=;i<=m;i++)
for(int j=i+;j<=m;j++)
if(solve(S[i],T[i],S[j],T[j],V[i],V[j])) Ans++;
printf("%d\n",Ans);
}
return ;
}
BZOJ 1906. 树上的蚂蚁的更多相关文章
- BZOJ.3784.树上的路径(点分治 贪心 堆)
BZOJ \(Description\) 给定一棵\(n\)个点的带权树,求树上\(\frac{n\times(n-1)}{2}\)条路径中,长度最大的\(m\)条路径的长度. \(n\leq5000 ...
- BZOJ 3784: 树上的路径
Description 问一棵树上前 \(k\) 大路径的边权. Sol 边分治. 非常感谢数据没有菊花图. 为了写写边分治试试然后就开了这道题. 边分治非常好想,选一条重边,分成两部分,然后分别求最 ...
- bzoj 3784: 树上的路径 堆维护第k大
3784: 树上的路径 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 88 Solved: 27[Submit][Status][Discuss] ...
- [BZOJ 1033] [ZJOI2008] 杀蚂蚁antbuster 【模拟!】
题目链接: BZOJ - 1033 题目分析 模拟!纯粹按照题目描述模拟! 这是一道喜闻乐见的经典模拟题! 我一共写了2遍,Debug 历时2天的所有晚自习 ... 时间超过 8h ... 我真是太弱 ...
- BZOJ 1316: 树上的询问( 点分治 + 平衡树 )
直接点分治, 用平衡树(set就行了...)维护. -------------------------------------------------------------------------- ...
- BZOJ1906树上的蚂蚁&BZOJ3700发展城市——RMQ求LCA+树链的交
题目描述 众所周知,Hzwer学长是一名高富帅,他打算投入巨资发展一些小城市. Hzwer打算在城市中开N个宾馆,由于Hzwer非常壕,所以宾馆必须建在空中,但是这样就必须建立宾馆之间的连接通道.机智 ...
- bzoj 4033 树上染色 - 树形动态规划
有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑 色,并将其他的N-K个点染成白色.将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的 ...
- [BZOJ 1033][ZJOI2008]杀蚂蚁antbuster
1033: [ZJOI2008]杀蚂蚁antbuster Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1200 Solved: 507[Submi ...
- bzoj 3757 树上莫队
感谢以下文章作者: http://blog.csdn.net/kuribohg/article/details/41458639 http://vfleaking.blog.163.com/blog/ ...
随机推荐
- Codeforces 939E Maximize ( 三分 || 二分 )
题意 : 给出两个操作,① 往一个序列集合(初始为空)里面不降序地添加数字.② 找出当前序列集合的一个子集使得 (子集的最大元素) - (子集的平均数) 最大并且输出这个最大差值 分析 : 首先关注 ...
- Kubernetes Deployment故障排除图解指南
个人K8s还在学习中,相关博客还没有写,准备学第二遍再开始学,发现这篇文章挺好,先转载一下. 原创: 白明的赞赏账户 下面是一个示意图,可帮助你调试Kubernetes Deployment(你可以 ...
- 【BZOJ2409】 地下车会
Description 小Y喜欢速度与激情,于是他参加了地下车会. 地下车会设有N 个分赛区,M种赛事.每个分赛区有C[i]场比赛.由于地下车会经营者想要赚到更多的钱,规定小 Y 必须参加某一些赛区 ...
- 【CF1243D&CF920E】0-1 MST(bfs,set)
题意:给定一张n个点的完全图,其中有m条边权为1其余为0,求最小生成树的权值和 n,m<=1e5 思路:答案即为边权为0的边连接的联通块个数-1 用set存图和一个未被选取的点的集合,bfs过程 ...
- 洛谷P3948 数据结构——题解
题目传送 感觉这道题秀了我一地的智商... 审题没审好,没确定带修改的操作中询问的次数<=1000,且max和min都是事先给好.不变的.想了半天线段树.分块,却忘了最基础的暴力. 写不出题时先 ...
- JMS学习五(ActiveMQ的本地事务)
1.ActiveMQ的本地事务 在一个JMS客户端,可以使用本地事务来组合消息的发送和接收.JMS Session接口提供了commit和rollback方法.事务提交意味着生产的所有消息被发送,消费 ...
- 5.Python注释(多行注释和单行注释)用法详解
Python单行注释 Python 中使用井号(‘#’)作为单行注释的符号,语法格式为: # 注释内容 也就是说,从符号‘#’处开始,直到换行处结束,此部分内容都作为注释的内容,当程序执行时,这部分内 ...
- Java中使用Scanner类进行键盘的输入详解
我们在使用Java写代码时,经常会遇到从键盘输入字符串等操作,这时候我们需要用到的是我们的Scanner类来实现获取用户从键盘上的输入操作. Scanner类是一个基于正则表达式的文本扫描器,它可以从 ...
- Java日期时间格式转换
1.Date转String 将日期格式化成指定的格式 public static String stampToDate(Date date) { SimpleDateFormat simpleDate ...
- jquery.fileupload-image-editor.js 中actions.resizeImage
https://github.com/ChuckForkJS/jQuery-File-Upload/blob/master/js/jquery.fileupload-image-editor.js a ...