题意:一棵树q次查询,每次查询给三个不同的点,要求计算到这三个点的比其他两个距离都要小的点数

题解:很明显的lca,倍增的找中点,关键是两个点的中点很好找,但是三个点不好找,我刚开始还准备分类讨论,后来发现巨麻烦,其实可以用线段树来维护算a的答案其实就是a在b下的答案和a在c下的答案的交集,可以用线段树区间求和区间查询做,每次更新完之后复原就不用memset线段树了

//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0) using namespace std; const double g=10.0,eps=1e-;
const int N=+,maxn=+,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f; vi v[N];
int dep[N],n,sz[N],fa[][N];
int le[N],ri[N],id[N],cnt;
void dfs(int u,int f)
{
le[u]=++cnt;
id[cnt]=u;
fa[][u]=f;
sz[u]=;
for(int i=;i<v[u].size();i++)
{
int x=v[u][i];
if(x!=f)dep[x]=dep[u]+,dfs(x,u),sz[u]+=sz[x];
}
ri[u]=cnt;
}
int lazy[N<<],val[N<<];
void pushdown(int l,int r,int rt)
{
if(lazy[rt]!=)
{
int m=(l+r)>>;
val[rt<<]+=(m-l+)*lazy[rt];
val[rt<<|]+=(r-m)*lazy[rt];
lazy[rt<<]+=lazy[rt];
lazy[rt<<|]+=lazy[rt];
lazy[rt]=;
}
}
void pushup(int rt)
{
val[rt]=val[rt<<]+val[rt<<|];
}
void build(int l,int r,int rt)
{
lazy[rt]=val[rt]=;
if(l==r)return ;
int m=(l+r)>>;
build(ls);build(rs);
}
void update(int c,int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
val[rt]+=(r-l+)*c;
lazy[rt]+=c;
return ;
}
pushdown(l,r,rt);
int m=(l+r)>>;
if(L<=m)update(c,L,R,ls);
if(m<R)update(c,L,R,rs);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)return val[rt];
pushdown(l,r,rt);
int m=(l+r)>>,ans=;
if(L<=m)ans+=query(L,R,ls);
if(m<R)ans+=query(L,R,rs);
return ans;
}
void init()
{
dep[]=;
cnt=;
dfs(,-);
build(,cnt,);
for(int i=;i<;i++)
for(int j=;j<=n;j++)
fa[i][j]=fa[i-][fa[i-][j]];
}
int lca(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
for(int i=;i<;i++)
if((dep[y]-dep[x])>>i&)
y=fa[i][y];
if(x==y)return x;
for(int i=;i>=;i--)
{
if(fa[i][x]!=fa[i][y])
{
x=fa[i][x];
y=fa[i][y];
}
}
return fa[][x];
}
int go(int u,int dis)
{
for(int i=;i>=;i--)
if(dis>=(<<i))
dis-=(<<i),u=fa[i][u];
return u;
}
int solve(int a,int b,int c)
{
int tle,tri,ans=;
if(dep[a]>=dep[b])
{
int dis=dep[a]+dep[b]-*dep[lca(a,b)];
int x=go(a,dis/);
if(dis%==)x=go(a,dis/-);
update(,le[x],ri[x],,cnt,);
tle=le[x],tri=ri[x];
}
else
{
int dis=dep[a]+dep[b]-*dep[lca(a,b)];
int x=go(b,dis/);
update(,,cnt,,cnt,);
update(-,le[x],ri[x],,cnt,);
tle=le[x],tri=ri[x];
}
if(dep[a]>=dep[c])
{
int dis=dep[a]+dep[c]-*dep[lca(a,c)];
int x=go(a,dis/);
if(dis%==)x=go(a,dis/-);
ans=query(le[x],ri[x],,cnt,);
}
else
{
int dis=dep[a]+dep[c]-*dep[lca(a,c)];
int x=go(c,dis/);
ans=query(,cnt,,cnt,);
ans-=query(le[x],ri[x],,cnt,);
}
if(dep[a]>=dep[b])update(-,tle,tri,,cnt,);
else update(-,,cnt,,cnt,),update(,tle,tri,,cnt,);
return ans;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=;i<=n;i++)v[i].clear();
for(int i=;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
v[a].pb(b),v[b].pb(a);
}
init();
int q;scanf("%d",&q);
while(q--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
// printf("%d\n",solve(b,a,c));
printf("%d %d %d\n",solve(a,b,c),solve(b,a,c),solve(c,a,b));
}
}
return ;
}
/***********************
1
9
1 2
1 3
1 4
2 5
2 6
2 7
6 8
6 9
2
1 2 8
2 1 4
***********************/

UVALive - 6712 lca+dfs序线段树的更多相关文章

  1. Educational Codeforces Round 6 E dfs序+线段树

    题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...

  2. 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

    3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] D ...

  3. Codeforces 343D Water Tree(DFS序 + 线段树)

    题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...

  4. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  5. POJ 3321 DFS序+线段树

    单点修改树中某个节点,查询子树的性质.DFS序 子树序列一定在父节点的DFS序列之内,所以可以用线段树维护. 1: /* 2: DFS序 +线段树 3: */ 4:   5: #include < ...

  6. 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

    题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...

  7. F - Change FZU - 2277 (DFS序+线段树)

    题目链接: F - Change FZU - 2277 题目大意: 题意: 给定一棵根为1, n个结点的树. 有q个操作,有两种不同的操作 (1) 1 v k x : a[v] += x, a[v ' ...

  8. BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

  9. BZOJ1103 [POI2007]大都市meg dfs序 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1103 题意概括 一棵树上,一开始所有的边权值为1,我们要支持两种操作: 1. 修改某一条边的权值为 ...

随机推荐

  1. Uboot mmc命令解析&NAND flash uboot命令详解

    转载:http://blog.csdn.net/simonjay2007/article/details/43198353 一:mmc的命令如下: 1:对mmc读操作 mmc read addr bl ...

  2. Jenkins节点配置页面,启动方法没有"Launch agent via Java Web Start"解决方法?

    Jenkins的配置从节点中默认没有Launch agent via JavaWeb Start,解决办法: 步骤: 1:打开"系统管理"——"Configure Glo ...

  3. 数据库连接池libzdb

    官网:http://www.tildeslash.com/libzdb/ A small, easy to use Open Source Database Connection Pool Libra ...

  4. bash 获取时间段内的日志内容

    需求,获取时段内的/var/log/messages文件内出现错误的消息,支持多行的消息,支持天,小时分钟,秒级的区间,可以修改监控的日志对象 #!/bin/bash if [ $# != 1 ] ; ...

  5. Salesforce视图与控制器之间的交互

    刚接触Salesforce,过程的确是比较艰难了,中文资料几乎没有,看英文资料学的效率却不高,不过看了一段时间的英文资料发现自己英语水平挺高不少啊,现在看都不用工具翻译,早知道就再次尝试报个6级,看下 ...

  6. java中元注解

    java中元注解有四个: @Retention @Target @Document @Inherited:  @Retention:注解的保留位置 @Retention(RetentionPolicy ...

  7. Tomcat的工作模式和运行模式

    (1)工作模式 Tomcat作为servlet容器,有三种工作模式: 1.独立的servlet容器,servlet容器是web服务器的一部分: 2.进程内的servlet容器,servlet容器是作为 ...

  8. 20145328 《Java程序设计》第8周学习总结

    20145328 <Java程序设计>第8周学习总结 教材学习内容总结 第十四章 NIO与NIO2 NIO使用频道(channel)来衔接数据节点,对数据区的标记提供了clear(),re ...

  9. C语言string.h常用函数总结

    void *memcpy(void *dest, const void *src, size_t n); 从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中. ...

  10. 【读书笔记】《深入浅出nodejs》第五章 内存控制

    海量请求+长时间运行 -> 内存控制 -> 一切资源高效循环利用 1. V8的垃圾回收机制与内存限制 在Node中通过JavaScript使用内存时,只能使用部分内存(64位系统下约1.4 ...