noip2016 天天爱跑步
没看过正解。。应该是些乱七八糟想不出来的东西
解法1:
首先,必须要做的是将每条路径拆成2个直的路径
那么对于那条从深度大的到深度小的路径 dep[x]-dep[y]应该等于观察时间
那么就可以在这些点打标记
那问题在于怎么找这些点
可以把深度为x的数组用vector搞出来
然后每次判断一下x里面的元素是否在他的子树中(判断一下lca就好了)
树剖判断一下每个点的覆盖次数
对于另一条路径同理做
代码:
解法2:
这个解法复杂度是可以分析出来的
首先还是把路径拆成两条
那么对于那条从深度大的到深度小的路径
考虑启发式合并
对于每个点维护一颗splay表示子树中出现的dep值的个数
将路径顶端和底端分别在该点打标记
访问到顶端时删除底端时插入
由于每一次向上会导致所有元素的权值变化所以可以加一个标记(插入时减掉这个值)
那么到查询点的时候就在splay上查询就可以了
那么复杂度是nlogn*splay的复杂度 也就是nlog^2n 不过splay的常数感觉这方法还是很虚啊。。。
还有就是splay的insert操作之后要splay一下
防止是这颗树的第一个节点
代码:
#include <bits/stdc++.h>
using namespace std;
#define maxn 6200000
#define maxn2 310000
int count2[maxn],leftson[maxn],rightson[maxn],fa[maxn],root[maxn2];
struct re{
int a,b,c;
}a[maxn2*];
int ans[maxn2],bz[maxn2][],dep[maxn2],vw[maxn2],head[maxn2],l,last[maxn2];
int hf[maxn2],cc[maxn2],dd[maxn2],lcaa[maxn2],num[maxn],num2,data[maxn];
int n,m;
vector<int> ve[maxn];
inline void updata(int x)
{
count2[x]=count2[leftson[x]]+count2[rightson[x]]+;
}
inline void rotate(int x,int y)
{
int father=fa[x];
if (y==)
{
rightson[father]=leftson[x];
if (leftson[x]) fa[leftson[x]]=father;
} else
{
leftson[father]=rightson[x];
if (rightson[x]) fa[rightson[x]]=father;
}
fa[x]=fa[father];
if (fa[father])
{
if (leftson[fa[father]]==father) leftson[fa[father]]=x;
else rightson[fa[father]]=x;
}
fa[father]=x;
if (y==) leftson[x]=father; else rightson[x]=father;
updata(father); updata(x);
}
inline void splay(int k,int x,int goal)
{
if (x==root[k]) return;
int father=fa[x];
while (father!=goal)
{
if (fa[father]==goal)
{
if (x==leftson[father]) rotate(x,); else rotate(x,);
} else
{
if (father==leftson[fa[father]])
{
if (x==leftson[father]) rotate(father,),rotate(x,);
else rotate(x,),rotate(x,);
} else
{
if (x==rightson[father]) rotate(father,),rotate(x,);
else rotate(x,),rotate(x,);
}
}
father=fa[x];
}
if (goal==) root[k]=x;
}
inline void dfs(int x,int y)
{
bz[x][]=y; dep[x]=dep[y]+;
int u=head[x];
while (u)
{
int v=a[u].b;
if (v!=y) dfs(v,x);
u=a[u].a;
}
}
inline int get_lca(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (int i=;i>=;i--)
if (dep[bz[x][i]]>=dep[y]) x=bz[x][i];
if (x==y) return(x);
for (int i=;i>=;i--)
if (bz[x][i]!=bz[y][i])
{
x=bz[x][i],y=bz[y][i];
}
return(bz[x][]);
}
inline void arr(int x,int y)
{
a[++l].a=head[x];
a[l].b=y;
head[x]=l;
}
inline void insert(int x,int v,int w)
{
int tmp=x;x=root[x];
while (x)
{
if (data[x]==v) break;
count2[x]++;
if (v<data[x])
{
if (!leftson[x]) break;
x=leftson[x];
} else
{
if (!rightson[x]) break;
x=rightson[x];
}
}
if (x!=&&data[x]==v) num[x]+=w; else
{
data[++num2]=v; count2[num2]=; fa[num2]=x;
num[num2]=w;
if (x!=)
{
if (v>data[x]) rightson[x]=num2;
else leftson[x]=num2;
}
splay(tmp,num2,);
}
}
inline void delete1(int k)
{
int x=leftson[root[k]];
if (x==)
{
root[k]=rightson[root[k]]; fa[root[k]]=; return;
}
while (rightson[x]) x=rightson[x];
splay(k,x,root[k]);
rightson[x]=rightson[root[k]];
if (rightson[root[k]]) fa[rightson[root[k]]]=x;
updata(x);
fa[x]=; root[k]=x;
}
inline int search(int x,int goal)
{
x=root[x];
while ()
{
if (data[x]==goal) return(x);
if (data[x]<goal)
{
if (!rightson[x]) return(x);
x=rightson[x];
}
else
{
if (!leftson[x]) return(x);
x=leftson[x];
}
}
}
inline void merge(int x,int y,int z)
{
while (root[x])
{
int tmp=data[root[x]]-last[y]+last[x];
int o=search(y,tmp);
if (o!=&&data[o]==tmp) num[o]+=num[root[x]];
else insert(y,tmp,num[root[x]]);
delete1(x);
}
root[z]=root[y]; last[z]=last[y];
}
inline void dfs2(int x,int fa,int lq)
{
int u=head[x],pp=ve[x].size();
for (int i=;i<=pp/-;i++)
if (!ve[x][i*+])
{
insert(x,ve[x][i*],);
}
while (u)
{
int v=a[u].b;
if (v!=fa)
{
dfs2(v,x,lq);
last[v]+=lq;
if (count2[root[x]]<count2[root[v]]) merge(x,v,x);
else merge(v,x,x);
}
u=a[u].a;
}
int tmp=search(x,vw[x]-last[x]);
if (data[tmp]==vw[x]-last[x]) ans[x]+=num[tmp];
for (int i=;i<=pp/-;i++)
if (ve[x][i*+])
{
int tmp=search(x,ve[x][i*]-last[x]);
if (num[tmp]>) num[tmp]--;
else
{
splay(x,tmp,);
delete1(x);
}
}
}
int main()
{
freopen("noip.in","r",stdin);
freopen("noip.out","w",stdout);
std::ios::sync_with_stdio(false);
cin>>n>>m;
int c,d;
for (int i=;i<=n-;i++)
cin>>c>>d,arr(c,d),arr(d,c);
for (int i=;i<=n;i++)
cin>>vw[i];
dfs(,);
for (int i=;i<=;i++)
for (int j=;j<=n;j++)
bz[j][i]=bz[bz[j][i-]][i-];
for (int i=;i<=m;i++)
{
cin>>c>>d;
cc[i]=c; dd[i]=d;
int w=get_lca(c,d);
lcaa[i]=w;
hf[i]=dep[c]-dep[w];
}
for (int i=;i<=m;i++)
{
ve[cc[i]].push_back(); ve[cc[i]].push_back();
ve[lcaa[i]].push_back(hf[i]); ve[lcaa[i]].push_back();
}
dfs2(,,);
memset(leftson,,sizeof(leftson));
memset(rightson,,sizeof(rightson));
memset(num,,sizeof(num));
memset(count2,,sizeof(count2));
memset(fa,,sizeof(fa));
memset(root,,sizeof(root));
memset(last,,sizeof(last)); num2=;
memset(data,,sizeof(data));
for (int i=;i<=n;i++)
{
vector<int> tmp; swap(tmp,ve[i]);
// ve[i].clear();
}
for (int i=;i<=m;i++)
{
ve[dd[i]].push_back(hf[i]+dep[dd[i]]-dep[lcaa[i]]);
ve[dd[i]].push_back();
ve[lcaa[i]].push_back(hf[i]);
ve[lcaa[i]].push_back();
}
dfs2(,,-);
for (int i=;i<=m;i++)
{
if (hf[i]==vw[lcaa[i]]) ans[lcaa[i]]--;
}
for (int i=;i<=n-;i++) cout<<ans[i]<<" ";
cout<<ans[n];
return ;
}
noip2016 天天爱跑步的更多相关文章
- [NOIp2016]天天爱跑步 线段树合并
[NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...
- [Noip2016]天天爱跑步 LCA+DFS
[Noip2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...
- 【LG1600】[NOIP2016]天天爱跑步
[LG1600][NOIP2016]天天爱跑步 题面 洛谷 题解 考虑一条路径\(S\rightarrow T\)是如何给一个观测点\(x\)造成贡献的, 一种是从\(x\)的子树内出来,另外一种是从 ...
- NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...
- BZOJ4719 [Noip2016]天天爱跑步
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- noip2016天天爱跑步
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点 ...
- bzoj 4719: [Noip2016]天天爱跑步
Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一 ...
- NOIP2016 天天爱跑步 80分暴力
https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...
- 4719: [Noip2016]天天爱跑步
Time Limit: 40 Sec Memory Limit: 512 MB Submit: 1986 Solved: 752 [Submit][Status][Discuss] Descripti ...
- NOIP2016 天天爱跑步 线段树合并_桶_思维题
竟然独自想出来了,好开心 Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r&q ...
随机推荐
- 微信小程序的页面渲染(if/for)
下面,粗略的介绍一下微信小程序的条件渲染.列表渲染.数据绑定等,详细的内容大家可以去看微信小程序的API,在此只做简单描述,希望能帮助到大家 条件渲染 <!--wxml--> <vi ...
- 如何利用 Python 完成验签操作
柠檬班Python8期的佑佑以及Python7期的掠掠同学昨天都私下问华华老师如何利用Python完成验签的操作. 今天我们就以佑佑的例子来跟大家进行简单的说明以及操作! 一.什么是验签: 用非常简单 ...
- python - 装饰器+描述符(给类添加属性且属性类型审核)
装饰器+描述符 实现给一个类添加属性且对添加的时,对属性进行类型审核: def zsq(**kwargs): def fun(obj): for i,j in kwargs.items(): seta ...
- AJAX请求头Content-type
发送json格式数据 xhr.setRequestHeader("Content-type","application/json; charset=utf-8" ...
- android 服务解析
https://blog.csdn.net/luoyanglizi/article/details/51586437 2.service和Thread的区别 定义上: thread是程序运行的最小单元 ...
- Jetson tk1 安装 usbtoserials 驱动(重新刷机)
一.tk1驱动包,文件系统和源码下载 截止2016年9月1号,tk1最版本为R21.5. (以下三个文件放在同一个文件夹下) 1.driver package(驱动包,相当于安装程序) https:/ ...
- SpringBoot三种配置Dubbo的方式
*必须首先导入dubbo-starter (1).使用SpringBoot配置文件(application.properties或application.yml) dubbo.application. ...
- C++学习8-面向对象编程基础(模板)
模板 模板是一种工具,模板可以使程序员能建立具有通用类型的函数库与类库: 模板具有两种不同的形式: 函数模板 类模板 函数模板 当一个add()函数接收两个参数,因为某种特定情况,所传入的实参数据类型 ...
- 常用css样式(布局)
兼容css3新属性 在css3中,我们可以使用prefixfree.min.js这个插件来自动为css3的相关属性加上兼容浏览器属性,使我们不用为每个css3新属性再加上属性(需要用到大量css3的项 ...
- springboot系列一、springboot产生背景及介绍
一.为什么用Springboot 长期以来 Java 的开发一直让人所诟病: ·Java 项目开发复杂度极其高: · Java 项目的维护非常困难: · 在云时代如何实现项目的快速部署以及快速启动: ...