P1600 天天爱跑步
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 天天爱跑步的更多相关文章
- [NOIP 2016D2T2/Luogu P1600] 天天爱跑步  (LCA+差分)
		
待填坑 Code //Luogu P1600 天天爱跑步 //Apr,4th,2018 //树上差分+LCA #include<iostream> #include<cstdio&g ...
 - [luogu]P1600 天天爱跑步[LCA]
		
[luogu]P1600 [NOIP 2016]天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...
 - 洛谷P1600 天天爱跑步(线段树合并)
		
小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn ...
 - P1600 天天爱跑步[桶+LCA+树上差分]
		
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵 ...
 - 洛谷 P1600 天天爱跑步
		
https://www.luogu.org/problemnew/show/P1600 (仅做记录) 自己的假方法: 每一次跑从a到b:设l=lca(a,b)对于以下产生贡献: a到l的链上所有的点( ...
 - 洛谷P1600 天天爱跑步——树上差分
		
题目:https://www.luogu.org/problemnew/show/P1600 看博客:https://blog.csdn.net/clove_unique/article/detail ...
 - Luogu:P1600   天天爱跑步
		
来一发清新的80行 树剖 $LCA$ + 树上差分 题解. -----from Judge 本题题意大概是给出一棵 n 个节点的树以及 m 条有向路径, 并且每个点 i 都有一个权值 $w[i]$,如 ...
 - 洛谷P1600 天天爱跑步
		
天天放毒... 首先介绍一个树上差分. 每次进入的时候记录贡献,跟出来的时候的差值就是子树贡献. 然后就可以做了. 发现考虑每个人的贡献有困难. 于是考虑每个观察员的答案. 把路径拆成两条,以lca分 ...
 - luogu P1600 天天爱跑步
		
传送门 1A此题暴祭 (下面记点\(x\)深度为\(de_x\),某个时间点记为\(w_x\)) 首先,每条路径是可以拆成往上和往下两条路径的 对于往上的路径,假设有个人往上跑,\(w_y\)在点\( ...
 
随机推荐
- Servlet----------ServletContext (重要)
			
1.ServletContext的概述 一个项目只有一个ServletContext对象!application 我们可以在N多个Servlet中获取这个唯一的对象,使用它来给多个Servlet传递数 ...
 - 002-redis-数据类型
			
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). 使用桌面工具查看,默认有16个库,Redis支持多 ...
 - react-native 相关问题
			
使用create-react-native-app时,报错,好像是npm版本不对,想问下npm怎么降低版本? npm install npm@4 -g 创建并启动项目 老方法1 创建项目 react ...
 - 输出log到指定文件
			
0:pom.xml中添加依赖 <!--log4j--> <!--有错误时,可能版本不对,或者依赖没有加全 'org.apache.logging.log4j:log4j-core:2 ...
 - 字符串最长子串匹配-dp矩阵[转载]
			
转自:https://blog.csdn.net/zls986992484/article/details/69863710 题目描述:求最长公共子串,sea和eat.它们的最长公共子串为ea,长度为 ...
 - [LeetCode] 394. Decode String_Medium tag: stack 666
			
Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string], where ...
 - IBatis 配置各种数据库
			
IBatis 与各种数据库之间的配置在providers.config这个文件下. <?xml version="1.0" encoding="utf-8" ...
 - 软件包管理:yum在线管理-yum命令
			
只要我们的电脑可以接入互联网,那么yum源就是配好的,yum命令可以直接使用. 列出的是服务器上全部的rpm包. 包名,包全名的概念只在rpm手动管理时有用. 关键字主要指包名,只要知道了关键字就可以 ...
 - 多项式函数插值:多项式形式函数求值的Horner嵌套算法
			
设代数式序列 $q_1(t), q_2(t), ..., q_{n-1}(t)$ ,由它们生成的多项式形式的表达式(不一定是多项式): $$p(t)=x_1+x_2q_1(t)+...x_nq_1(t ...
 - Leetcode: Repeated DNA Sequence
			
All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACG ...