zoukankan      html  css  js  c++  java
  • luogu P1600 天天爱跑步

    膜你赛T3考了这题的简化版,当场自闭。就此把此类题目总结一下。

    膜你赛题意是这样的:相当于这个题最后问每个运动员被多少个观察员观察到。我们考虑把每条路径拆成向上和向下两条,本质相同,我们以向上路径举例。发现路径上满足 (dep[S]-dep[x]=x)(S) 表示路径起点) 的 (x) 都可以获得 (1) 的贡献。我们差分一下,最后再一遍 (dfs) 统计答案(离线)就行了。

    这个题和膜你赛题的区别呢,就是此题是一个标记对根到它产生贡献,所以最后统计答案的时候是统计子树。现在有个非常骚的操作:统计差值。由于我们提前知道了我们要求的量是什么,我们可以在 (dfs) 开始的时候记录这个初值,在 (dfs) 结束时看看这个值现在长什么样子,最后取个差就是我们想要的贡献了。这个 trick 好像以前也见过,但因为记忆力低下考场上并没有想起来什么。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<vector>
    
    using namespace std;
    
    const int N=300009;
    int n,m,head[N],cnt,x[N],y[N],w[N],p[N],dep[N],f[N][30],L[N],tax[N*4],ans[N];
    struct Edge
    {
    	int nxt,to;
    }g[N*2];
    vector <pair<int,int> > b[N];
    
    void add(int from,int to)
    {
    	g[++cnt].nxt=head[from];
    	g[cnt].to=to;
    	head[from]=cnt;
    }
    
    void init()
    {
    	scanf("%d %d",&n,&m);
    	for (int i=1,X,Y;i<n;i++)
    		scanf("%d %d",&X,&Y),add(X,Y),add(Y,X);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&w[i]);
    	for (int i=1;i<=m;i++)
    		scanf("%d %d",&x[i],&y[i]);
    }
    
    void dfs(int x,int fa)
    {
    	for (int i=head[x];i;i=g[i].nxt)
    	{
    		int v=g[i].to;
    		if(v==fa)
    			continue;
    		dep[v]=dep[x]+1,f[v][0]=x;
    		dfs(v,x);
    	}
    }
    
    int LCA(int x,int y)
    {
    	if(dep[x]!=dep[y])
    	{
    		if(dep[x]<dep[y])
    			swap(x,y);
    		int k=dep[x]-dep[y];
    		for (int i=20;i>=0;i--)
    			if(k>=1<<i)
    				k-=1<<i,x=f[x][i];
    	}
    	if(x==y) return x;
    	for (int i=20;i>=0;i--)
    		if(f[x][i]!=f[y][i])
    			x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    
    void DFS(int x,int fa)
    {
    	int qwq=tax[p[x]];
    	for (int i=0;i<b[x].size();i++)
    		tax[b[x][i].first]+=b[x][i].second;
    	for (int i=head[x];i;i=g[i].nxt)
    	{
    		int v=g[i].to;
    		if(v==fa)
    			continue;
    		DFS(v,x);
    	}
    	ans[x]+=qwq-tax[p[x]];
    }
    
    void work()
    {
    	dfs(1,-1);
    	for (int j=1;j<=20;j++)
    		for (int i=1;i<=n;i++)
    			f[i][j]=f[f[i][j-1]][j-1];
    //	for (int i=1;i<=n;i++,puts(""))
    //		for (int j=i;j<=n;j++)
    //			printf("%d ",LCA(i,j));
    	for (int i=1;i<=m;i++)
    		L[i]=LCA(x[i],y[i]);
    	for (int i=1;i<=n;i++)
    		p[i]=dep[i]+w[i];
    	for (int i=1;i<=m;i++)
    		b[x[i]].push_back(make_pair(dep[x[i]],-1)),
    		b[f[L[i]][0]].push_back(make_pair(dep[x[i]],1));
    	add(0,1);
    	DFS(0,-1);
    	for (int i=0;i<=n;i++)
    		p[i]=w[i]-dep[i]+N,b[i].clear();
    	for (int i=1;i<=m;i++)
    	{
    		int dis=dep[x[i]]-2*dep[L[i]]+N;
    		b[y[i]].push_back(make_pair(dis,-1)),
    		b[L[i]].push_back(make_pair(dis,1));
    	}
    	DFS(0,-1);
    	for (int i=1;i<=n;i++)
    		printf("%d ",ans[i]);puts("");
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    Python --- Python的简介
    Python---subline的安装与设置
    算法进阶指南(DFS和BFS)--- 小猫爬山
    算法进阶指南(递归)--- 递归实现排列型枚举
    算法进阶指南(递归)--- 递归实现组合型枚举
    算法进阶指南(递归)--- 递归实现指数型枚举
    linux命令行调试邮件服务器
    01_8_session
    01_7_cookies
    03_9_继承中的构造方法
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13670902.html
Copyright © 2011-2022 走看看