update 2019.9.29

分解成为\(u->lca\)和\(lca->v\)

得到两个式子,需要统计子树内部的信息。

用差分维护下,差分维护类似于这个前置题

#include <bits/stdc++.h>
using namespace std;
const int _=5e5+7;
int read() {
int x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
int n,m,w[_],S[_],T[_],lca[_],tong[_*3],ans[_];
struct node {int v,nxt,q;}e[_<<1];
struct edge {int x,y;edge(int a=0,int b=0) {x=a,y=b;}};
vector<edge> ad[_*4];
int head[_],tot;
void add(int u,int v) {
e[++tot].v=v;
e[tot].nxt=head[u];
head[u]=tot;
}
int son[_],dep[_],fa[_],siz[_],top[_];
void dfs1(int u,int f) {
fa[u]=f;
dep[u]=dep[f]+1;
siz[u]=1;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v==f) continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v]) son[u]=v;
}
}
void dfs2(int u,int topf) {
top[u]=topf;
if(!son[u]) return;
dfs2(son[u],topf);
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(!top[v]) dfs2(v,v);
}
}
int LCA(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
} return dep[x]<dep[y]?x:y;
}
void solve1(int u,int fa) {
int A=tong[dep[u]+w[u]];
for(int i=0;i<(int)ad[u].size();++i)
tong[ad[u][i].x]+=ad[u][i].y;
for(int i=head[u];i;i=e[i].nxt)
if(e[i].v!=fa) solve1(e[i].v,u);
int B=tong[dep[u]+w[u]];
ans[u]+=B-A;
}
void solve2(int u,int fa) {
int A=tong[w[u]-dep[u]+2*n];
for(int i=0;i<(int)ad[u].size();++i)
tong[ad[u][i].x]+=ad[u][i].y;
for(int i=head[u];i;i=e[i].nxt)
if(e[i].v!=fa) solve2(e[i].v,u);
int B=tong[w[u]-dep[u]+2*n];
ans[u]+=B-A;
}
int main() {
n=read(),m=read();
for(int i=1;i<n;++i) {
int u=read(),v=read();
add(u,v),add(v,u);
}
for(int i=1;i<=n;++i) w[i]=read();
dfs1(1,0),dfs2(1,1);
for(int i=1;i<=m;++i) S[i]=read(),T[i]=read(),lca[i]=LCA(S[i],T[i]);
for(int i=1;i<=m;++i) {
ad[S[i]].push_back(edge(dep[S[i]],1));
ad[fa[lca[i]]].push_back(edge(dep[S[i]],-1));
}
solve1(1,0);
for(int i=1;i<=n*3;++i) ad[i].clear();
for(int i=1;i<=m;++i) {
ad[lca[i]].push_back(edge(dep[S[i]]-2*dep[lca[i]]+2*n,-1));
ad[T[i]].push_back(edge(dep[S[i]]-2*dep[lca[i]]+2*n,1));
}
solve2(1,0);
for(int i=1;i<=n;++i) printf("%d ",ans[i]);
return 0;
}

lca真心不太会,这里只介绍60分做法,100的太难辣简单了就不介绍了

n<=1000

zz回溯爆搜

S[i]全部相等

这dfs序都不用lca的,2333,差分,然后输出判断一下是否是0(1到i的时间是固定的)

退化成一条链子

一个点i的ans就是i-time[i]和i+tim[i]的起点个数(当然要合法啦)

乱搞就好了,这里写的nlogn的

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=300000;
const int maxn_25=1000;
struct edge {
int v,nxt;
}e[maxn<<1];
struct node {
int x,id;
bool operator < (const node b) const {
return x>b.x;
}
};
struct node1 {
int x,id;
bool operator < (const node1 b) const {
return x<b.x;
}
};
int head[maxn<<1],tot;
int tim[maxn],n,m,S[maxn],T[maxn],deep[maxn<<1]; int pd_25,ans_25[maxn_25]; //baoli 25 zhuanyong int tot_a,a_c[maxn<<1],find_a[maxn],ans_c[maxn];//all s == 1 zhuanyong
int vis[maxn<<1],cf[maxn<<1],dsr[maxn<<1]; int ans[maxn];
void add_edge(int u,int v) {
e[++tot].v=v;
e[tot].nxt=head[u];
head[u]=tot;
}
inline int read() {
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9')
{if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9')
{x=(x<<3)+(x<<1)+s-'0',s=getchar();}
return x*f;
}
void dfs_25(int u,int f,int end,int cnt) {
if(u==end) {
if(cnt==tim[u]) ans_25[u]++;
pd_25=1;
return;
}
if(pd_25) return;
if(cnt==tim[u]) ans_25[u]++;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v==f) continue;
dfs_25(v,u,end,cnt+1);
if(pd_25) return;
}
if(cnt==tim[u]) ans_25[u]--;
}
void dfs_deep(int u,int f,int cnt) {
deep[u]=cnt;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(f==v) continue;
dfs_deep(v,u,cnt+1);
}
}
void dfs_xu(int u,int f) {
a_c[++tot_a]=0;
find_a[u]=tot_a;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v==f) continue;
dfs_xu(v,u);
}
a_c[++tot_a]=0;
vis[tot_a]=u;
dsr[u]=tot_a;
}
int main() {
n=read(),m=read();
for(int i=1;i<n;++i) {
int x=read(),y=read();
add_edge(x,y);
add_edge(y,x);
}
for(int i=1;i<=n;++i)
tim[i]=read();
for(int i=1;i<=m;++i)
S[i]=read(),T[i]=read(); //baoli_25
if(n<=1000) {
for(int i=1;i<=m;++i) {
pd_25=0;
dfs_25(S[i],0,T[i],0);
}
for(int j=1;j<=n;++j)
printf("%d ",ans_25[j]);
return 0;
} int wakaka=1;
for(int i=1;i<=m;++i)
if(S[i]!=1) wakaka=0;
if(wakaka)
{
//all S[i]==1 fen==20
dfs_deep(1,0,0);//1 -> i deep
dfs_xu(1,0);
//chafen
for(int i=1;i<=m;++i) {
//1->i
cf[find_a[S[i]]]++;
cf[find_a[T[i]]+1]--;
}
//qiouhe
for(int i=1;i<=tot_a;++i) {
a_c[i]=a_c[i-1]+cf[i];
}
for(int i=1;i<=n;++i) {
if(deep[i]==tim[i])
printf("%d ",a_c[find_a[i]]-a_c[dsr[i]]);
else
printf("0 ");
}
return 0;
} priority_queue<node> q;
for(int i=1;i<=m;++i)
{
if(S[i] > T[i]) continue;
dsr[S[i]]++;
node x;
x.x=T[i]+1;
x.id=S[i];
q.push(x);
}
for(int i=1;i<=n;++i)
{
while(!q.empty()&&q.top().x==i)
dsr[q.top().id]--,q.pop();
if(i-tim[i]>=1)
ans[i]+=dsr[i-tim[i]];
} priority_queue< node1 > qq;
memset(dsr,0,sizeof(dsr));
for(int i=1;i<=m;++i)
{
if(S[i] <= T[i]) continue;
dsr[S[i]]++;
node1 x;
x.x=T[i]-1;
x.id=S[i];
qq.push(x);
}
for(int i=n;i>=1;--i)
{
while(!qq.empty()&&qq.top().x==i)
dsr[qq.top().id]--,qq.pop();
// puts("debug");
// for(int j=1;j<=n;++j)
// cout<<dsr[j]<<" ";puts("");
if(i+tim[i]<=n)
ans[i]+=dsr[i+tim[i]];
} for(int i=1;i<=n;++i)
printf("%d ",ans[i]);
return 0;
}

P1600 天天爱跑步的更多相关文章

  1. [NOIP 2016D2T2/Luogu P1600] 天天爱跑步 (LCA+差分)

    待填坑 Code //Luogu P1600 天天爱跑步 //Apr,4th,2018 //树上差分+LCA #include<iostream> #include<cstdio&g ...

  2. [luogu]P1600 天天爱跑步[LCA]

    [luogu]P1600 [NOIP 2016]天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...

  3. 洛谷P1600 天天爱跑步(线段树合并)

    小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn ...

  4. P1600 天天爱跑步[桶+LCA+树上差分]

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵 ...

  5. 洛谷 P1600 天天爱跑步

    https://www.luogu.org/problemnew/show/P1600 (仅做记录) 自己的假方法: 每一次跑从a到b:设l=lca(a,b)对于以下产生贡献: a到l的链上所有的点( ...

  6. 洛谷P1600 天天爱跑步——树上差分

    题目:https://www.luogu.org/problemnew/show/P1600 看博客:https://blog.csdn.net/clove_unique/article/detail ...

  7. Luogu:P1600 天天爱跑步

    来一发清新的80行 树剖 $LCA$ + 树上差分 题解. -----from Judge 本题题意大概是给出一棵 n 个节点的树以及 m 条有向路径, 并且每个点 i 都有一个权值 $w[i]$,如 ...

  8. 洛谷P1600 天天爱跑步

    天天放毒... 首先介绍一个树上差分. 每次进入的时候记录贡献,跟出来的时候的差值就是子树贡献. 然后就可以做了. 发现考虑每个人的贡献有困难. 于是考虑每个观察员的答案. 把路径拆成两条,以lca分 ...

  9. luogu P1600 天天爱跑步

    传送门 1A此题暴祭 (下面记点\(x\)深度为\(de_x\),某个时间点记为\(w_x\)) 首先,每条路径是可以拆成往上和往下两条路径的 对于往上的路径,假设有个人往上跑,\(w_y\)在点\( ...

随机推荐

  1. Jena 操作 RDF 文件

    1. RDF 入门 RDF(Resource Description Framework)是由W3C规定的,描述资源(resource)的数据模型(data model),: RDF 使用Web标识符 ...

  2. 对SQL SERVER数据类型理解最好的一篇文章

    字符串前加N SQL SERVER中生成的语句中,字符串前加N,N 前缀必须是大写字母,是Unicode编码的意思. 一般来说,英文字符是一个字节组成,但是国际上的字太多了,因此就用两个字节来表示字符 ...

  3. Python3学习之路~2.1 列表、元组操作

    列表 列表是我们以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作. 定义列表(list) names=['Amy','Bob','Cindy','David'] 通过下标访问列 ...

  4. 【java】System.out重定向到文件,并重定向会console上

    重定向到文件: System.setOut(new PrintStream(new File("data\\train.1.scale"))); 重定向回console: //把输 ...

  5. os模块的使用

    python编程时,经常和文件.目录打交道,这是就离不了os模块.os模块包含普遍的操作系统功能,与具体的平台无关.以下列举常用的命令 1. os.name()——判断现在正在实用的平台,Window ...

  6. Django的基本开发环境配置和MTV模型

    一.MTV模型 Django的MTV分别代表: Model(模型):负责业务对象与数据库的对象(ORM) Template(模版):负责如何把页面展示给用户 View(视图):负责业务逻辑,并在适当的 ...

  7. redis桌面管理工具 redis-desktop-manager使用指南(转)

    版权声明:转自 http://blog.csdn.net/li396864285/article/details/54629898     概要:一款好用的Redis桌面管理工具,支持命令控制台操作, ...

  8. no-siteapp 和 no-transform

    简单的说,是禁止转码 . 举个通俗的例子. 你建了一栋房子(网站),百度说我给你做个大门,但是大门上要有我的广告 你不愿意,就建立了一条路叫no-transform 别人去你家走这条路就行了 后来百度 ...

  9. python 循环队列的实现

    最近在做一个东西的时候发现需要用到循环队列,实现先进先出(FIFO),不断往里面添加数据,当达到某个限定值时,最先进去的出去,然后再添加.之后需要对队列里面的内容进行一个筛选,作其他处理.首先我想到了 ...

  10. ajax 拦截器设置请求头

    使用vue-resource时,往headers里添加token后,post方法会自动变成options? Vue.http.interceptors.push(function(request, n ...