题解:

因为w大于1,所以,题意就是,有多少(x,z),存在x到z的路径上,有一个x<y<z的y

w没用的其实。

树上路径问题,有什么方法吗?

1.树链剖分。这个主要方便处理修改操作。

2.点分治,对于静态无修改点树上统计,非常好用。

3.一些其他的:

利用lca,dfs序,判断点在路径上,点在子树里一些情况。

倍增,处理fa[N][20],dis[N][20] ,

二分再套一个倍增?

4.还有一些灵活应变的:

例如:拆路径为x到lca,lca到y,可以在x,y记录一些lca的信息,把路径就变成了点。

例题:牛客网NOIP赛前集训营-提高组(第一场)T3

这个题,静态无修树上统计,就点分治了。

还可以再带一个log

那么当前层的重心G,统计过G路径。

树形背包思想,直接统计z能和之前的那些x凑成点对,记录x到G路径上的大于x最小的编号nx(因为是存在,不是任意嘛)

然后记录z到G路径上小于z的最大编号pz

如果pz>x,那么可以

如果nx<y,那么可以

但是pz<nx的情况被算重了。去重要用二维数据结构两个log就TLE了。

正难则反。考虑所有的点对。C(n,2)

对于x到z路径上都比x,z小的去掉,都比x、z大的去掉。就可以了。

具体来说,维护一个树状数组,

以去掉路径上都比x、z小的为例:

之前访问的作为x,如果x到根节点的路径上(包括根)最大值(不存在就是一个任意问题了)小于x,把x位置++

dfs统计,对于z,如果G到z路径上的最大值mx小于z,统计query(z-1)-query(mx)

表示得到编号在mx+1到z-1的x,且x到根路径上的最大值小于x的x数量。

就可以去掉这部分。

当然,因为G儿子的循环顺序,必须正序循环一遍,再倒序循环一遍。当前都作为z,之前的作为x,一定不会漏

另一个都比x,z大的同理。

而且之后统计路径上比x、z都大的情况不会算重。

小细节:

1.C(n,2)会爆int

2.子树的sz不是开始统计的sz,递归之前,必须从新的根即重心G再dfs统计sz

3.点分治一定要时刻控制:if(vis[e[i].to]) continue 否则T得飞起,WA的痛快。

4.发现,对于每条边的两端点对,会被减掉两次。

所以,ans开始还要加上(n-1)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=+;
const int inf=0x3f3f3f3f;
ll n;
int rt,nowsz;
bool vis[N];
int mxsz[N],sz[N];
int f[N];
void add(int x,int c){//树状数组
for(;x<=n;x+=x&(-x)) f[x]+=c;
}
int query(int x){
int ret=;for(;x;x-=x&(-x)) ret+=f[x];return ret;
}
int sta[N],top;
int mxid[N],miid[N];//路径上编号最小值,最大值
ll ans;
struct node{
int nxt,to;
int pre;
}e[*N];
int hd[N],cnt;
int las[N];
void con(int x,int y){//注意建立双向邻接表,便于反过来dfs
if(hd[x]&&e[hd[x]].nxt==) las[x]=hd[x];
e[++cnt].nxt=hd[x];
e[hd[x]].pre=cnt;
e[cnt].to=y;
hd[x]=cnt;
}
void dfs0(int x,int fa){//dfs0找根
sta[++top]=x;
mxid[x]=;mxsz[x]=;
miid[x]=;
sz[x]=;
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
if(vis[y]) continue;
dfs0(y,x);
sz[x]+=sz[y];
mxsz[x]=max(mxsz[x],sz[y]);
}
if(mxsz[x]<=nowsz/&&(nowsz-sz[x])<=nowsz/) rt=x;
}
void fsz(int x,int fa){//找完rt更新sz
sz[x]=;
for(int i=hd[x];i;i=e[i].nxt){
if(vis[e[i].to]) continue;
if(e[i].to!=fa){
fsz(e[i].to,x);
sz[x]+=sz[e[i].to];
}
}
}
void dfs1(int x,int mx,int fa){//dfs1统计答案,对于路径上的点都比x,z小的。
mxid[x]=mx;
if(mx<x) ans-=(query(x-)-query(mx));
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
if(vis[y]) continue;
dfs1(y,max(mx,x),x);
}
}
void upda1(int x,int fa){//dfs1之后,更新子树
if(mxid[x]<x) add(x,);
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
if(vis[y]) continue;
upda1(y,x);
}
}
void srt1(int x,int fa,int mx){//根比较麻烦,单独处理
//if(mx<rt&&x>rt) ans--;
if(mx<rt&&x>mx) ans--;
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
if(vis[y]) continue;
srt1(y,x,max(mx,x));
}
}
void dvi1(int in){//点分治1
dfs0(in,);
fsz(rt,);
for(int i=hd[rt];i;i=e[i].nxt){
if(vis[e[i].to]) continue;
dfs1(e[i].to,rt,rt);
upda1(e[i].to,rt);
}
for(int i=;i<=top;i++){
int x=sta[i];
if(x==rt) continue;
if(mxid[x]<x) add(x,-);
}
for(int i=las[rt];i;i=e[i].pre){//反向再处理一次
if(vis[e[i].to]) continue;
dfs1(e[i].to,rt,rt);
upda1(e[i].to,rt);
}
for(int i=hd[rt];i;i=e[i].nxt){
if(vis[e[i].to]) continue;
srt1(e[i].to,rt,);
}
while(top){
int x=sta[top--];
if(x==rt) continue;
if(mxid[x]<x) add(x,-);
}
vis[rt]=;
for(int i=hd[rt];i;i=e[i].nxt){
int y=e[i].to;
if(vis[y]) continue;
nowsz=sz[y];
dvi1(y);
}
}
//以下是x,z路径上点都比较大的,同理
void dfs2(int x,int mi,int fa){
miid[x]=mi;
if(mi>x) ans-=(query(mi-)-query(x));
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
if(vis[y]) continue;
dfs2(y,min(mi,x),x);
}
}
void upda2(int x,int fa){
if(miid[x]>x) add(x,);
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
if(vis[y]) continue;
upda2(y,x);
}
}
void srt2(int x,int fa,int mi){
if(mi>rt&&x<mi) ans--;
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
if(vis[y]) continue;
srt2(y,x,min(mi,x));
}
}
void dvi2(int in){
dfs0(in,);
fsz(rt,);
for(int i=hd[rt];i;i=e[i].nxt){
if(vis[e[i].to]) continue;
dfs2(e[i].to,rt,rt);
upda2(e[i].to,rt);
}
for(int i=;i<=top;i++){
int x=sta[i];
if(x==rt) continue;
if(miid[x]>x) add(x,-);
}
for(int i=las[rt];i;i=e[i].pre){
if(vis[e[i].to]) continue;
dfs2(e[i].to,rt,rt);
upda2(e[i].to,rt);
}
for(int i=hd[rt];i;i=e[i].nxt){
if(vis[e[i].to]) continue;
srt2(e[i].to,rt,inf);
}
while(top){
int x=sta[top--];
if(x==rt) continue;
if(miid[x]>x) add(x,-);
}
vis[rt]=;
for(int i=hd[rt];i;i=e[i].nxt){
int y=e[i].to;
if(vis[y]) continue;
nowsz=sz[y];
dvi2(y);
}
}
int main(){
scanf("%lld",&n);
int x,y,z;
for(int i=;i<=n-;i++){
scanf("%d%d%d",&x,&y,&z);
con(x,y);con(y,x);
}
ans=(n-)*n/ + (n-);//warning warning warning!!!
nowsz=n;
dvi1(); memset(vis,,sizeof vis);//解开封锁
top=;
nowsz=n;
dvi2();
printf("%lld",ans);
return ;
}

EOJ 306 树上问题的更多相关文章

  1. EOJ Monthly 2018.8 D. Delivery Service-树上差分(边权/边覆盖)(边权转点权)(模板题)

    D. Delivery Service 单测试点时限: 2.5 秒 内存限制: 512 MB EOJ Delivery Service Company handles a massive amount ...

  2. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  3. BZOJ 3784: 树上的路径

    Description 问一棵树上前 \(k\) 大路径的边权. Sol 边分治. 非常感谢数据没有菊花图. 为了写写边分治试试然后就开了这道题. 边分治非常好想,选一条重边,分成两部分,然后分别求最 ...

  4. HDU 2376 树形dp|树上任意两点距离和的平均值

    原题:http://acm.hdu.edu.cn/showproblem.php?pid=2376 经典问题,求的是树上任意两点和的平均值. 这里我们不能枚举点,这样n^2的复杂度.我们可以枚举每一条 ...

  5. LCA + 树状数组 + 树上RMQ

    题目链接:http://poj.org/problem?id=2763 思路:首先求出树上dfs序列,并且标记树上每个节点开始遍历以及最后回溯遍历到的时间戳,由于需要修改树上的某两个节点之间的权值,如 ...

  6. HDU 2545 树上战争 (并查集+YY)

    题意:给一棵树,如果树上的某个节点被某个人占据,则它的所有儿子都被占据,lxh和pfz初始时分别站在两个节点上,lxh总是先移动 ,谁当前所在的点被另一个人占据,他就输了比赛,问谁能获胜 比较有意思的 ...

  7. poj1155 TELE (树上的背包)

    题目链接:http://poj.org/problem?id=1155 题意:给定一棵树,1为根结点表示电视台,有m个叶子节点表示客户,有n-m-1个中间节点表示中转站,每条树边有权值.现在要在电视台 ...

  8. Codevs 2370 小机房的树 LCA 树上倍增

    题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...

  9. Subway Icon Set – 306个像素完美的特制图标

    这个图标集是306个优化的像素完美,精雕细琢的图标.为这些设备进行了优化:iOS.Windows Phone.Windows 8 and BlackBerry 10,提供 PNG, SVG, XALM ...

随机推荐

  1. JavaWeb 消息总线框架 Saka V0.0.1 发布

    端午闲着无聊,自己撸了一个简单的框架,可以实现在使用SendClient发送消息,在Spring容器中,符合该消息机制的接收器将能够被执行,目前Saka处于0.0.1版本[Saka-GIthub地址( ...

  2. Python HTML解析器BeautifulSoup(爬虫解析器)

    BeautifulSoup简介 我们知道,Python拥有出色的内置HTML解析器模块——HTMLParser,然而还有一个功能更为强大的HTML或XML解析工具——BeautifulSoup(美味的 ...

  3. 浅谈TCP IP协议栈(一)入门知识【转】

    说来惭愧,打算写关于网络方面的知识很久了,结果到今天才正式动笔,好了,废话不多说,写一些自己能看懂的入门知识,对自己来说是一种知识的总结,也希望能帮到一些想了解网络知识的童鞋. 万事开头难,然后中间难 ...

  4. 【记录】文件加密软件 Gilisoft File Lock Pro v11.0 中文注册版

    ---恢复内容开始--- GiliSoft File Lock Pro 是一款优秀的加密工具,用它可以隐藏或加密文件.文件夹.磁盘分区,而且被加密的文件不会因为被加密(忘记密码)而丢失,可算是很安全的 ...

  5. SQLServer之创建DML AFTER INSERT触发器

    DML AFTER INSERT触发器创建原理 触发器触发时,系统自动在内存中创建deleted表或inserted表,内存中创建的表只读,不允许修改,触发器执行完成后,自动删除. insert触发器 ...

  6. 英语口语练习系列-C21-美式幽默

    1. 基础词汇 1.1 back [bæk] n. 后背 on the back 靠着背 sleep on the back 仰着睡 back of the chair 椅子的后背 stab sb. ...

  7. Java学习笔记记录(一)

    1.Java编写的一个基本结构 1 public class demo{ //以下包含权限修饰符.静态修饰符.返回值修饰符以及主方法main() 2 public static void main(S ...

  8. 推荐一套Angular2的UI模板

    Core UI Core UI是一款基于Bootstrap4的UI模板,有html.angular2,react和vue版.我是在使用angular2版本中发现其项目结构不符合angular风格指南推 ...

  9. Kafka 0.11.0.0 实现 producer的Exactly-once 语义(中文)

    很高兴地告诉大家,具备新的里程碑意义的功能的Kafka 0.11.x版本(对应 Confluent Platform 3.3)已经release,该版本引入了exactly-once语义,本文阐述的内 ...

  10. 实现element-ui中table点击一行展开

    转:https://www.jianshu.com/p/e51ba4cb11d6 先上效果   效果图 三要素 1.row-click 点击行 2.ref 自行了解vue 3.toggleRowExp ...