题意

分析

对一个(s,t)查询,令f=lca(s,t),则操作可化为(s,f),(f,t)。

考虑观察到的情况,若x在s到t的路径上,且x观察到,则
\[
\textrm{dep}_s-\textrm{dep}_x=w_x\\
\textrm{dep}_s=\textrm{dep}_x+w_x
\]
或者
\[
\textrm{dep}_t+\textrm{dep}_s-2\textrm{dep}_f-(\textrm{dep}_t-\textrm{dep}_x)=w_x\\
\textrm{dep}_s-2\textrm{dep}_f=w_x-\textrm{dep}_x
\]
那么相当于在x的子树中查询等于x相关的值的个数。

考虑树上差分,在s或t处加1,在f处减1,然后对每个权值建一个以dfn序为下标的线段树,维护加减1的个数。
枚举树上节点,查询子树即可。

时间复杂度\(O(m \log n + n \log n)\)

代码

注意数组的范围。

分成2条链操作的时候,1次统计f,1次不统计f。
第2种情况时为了数组下标大于0,要加上n+1。

注意fa[f]=0的情况,不应该操作线段树。

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#define rg register
#define il inline
#pragma GCC optimize ("O3")
using namespace std;
template<class T> inline T read(T&x)
{
    T data=0;
    int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;

const int MAXN=3e5+7;
int w[MAXN],t[MAXN];

struct Edge
{
    int nx,to;
}E[MAXN<<1];
int head[MAXN],ecnt;

il void addedge(rg int x,rg int y)
{
    E[++ecnt].to=y;
    E[ecnt].nx=head[x],head[x]=ecnt;
}

int fa[MAXN],dep[MAXN],siz[MAXN],son[MAXN];

il void dfs1(rg int x,rg int f)
{
    fa[x]=f,dep[x]=dep[f]+1,siz[x]=1;
    for(rg int i=head[x];i;i=E[i].nx)
    {
        rg int y=E[i].to;
        if(y==f)
            continue;
        dfs1(y,x);
        siz[x]+=siz[y];
        if(siz[y]>siz[son[x]])
            son[x]=y;
    }
}

int top[MAXN];
int dfn[MAXN],clk;

il void dfs2(rg int x,rg int tp)
{
    top[x]=tp;
    dfn[x]=++clk;
    if(!son[x])
        return;
    dfs2(son[x],tp);
    for(rg int i=head[x];i;i=E[i].nx)
    {
        rg int y=E[i].to;
        if(y==fa[x]||y==son[x]) // edit 1
            continue;
        dfs2(y,y);
    }
}

il int lca(rg int x,rg 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;
}

struct Quiz
{
    int s,t,lca;
}Q[MAXN];
int ans[MAXN];

int root[MAXN*3],tcnt;
int ql,qr,v;
struct SegTree
{
    int sumv[MAXN*20];
    int L[MAXN*20],R[MAXN*20];

    il void add(rg int&now,rg int l,rg int r)
    {
        if(!now)
            now=++tcnt;
        sumv[now]+=v;
        if(l==r)
            return;
        rg int mid=(l+r)>>1;
        if(ql<=mid)
            add(L[now],l,mid);
        else
            add(R[now],mid+1,r);
    }

    il int qsum(rg int now,rg int l,rg int r)
    {
        if(!now)
            return 0;
        if(ql<=l&&r<=qr)
            return sumv[now];
        rg int mid=(l+r)>>1;
        if(qr<=mid)
            return qsum(L[now],l,mid);
        if(ql>=mid+1)
            return qsum(R[now],mid+1,r);
        return qsum(L[now],l,mid)+qsum(R[now],mid+1,r);
    }
}T;

il void init()
{
    tcnt=0;
    memset(root,0,sizeof root);
    memset(&T,0,sizeof T);
}

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    rg int n,m;
    read(n);read(m);
    for(rg int i=1,x,y;i<n;++i)
    {
        read(x);read(y);
        addedge(x,y);
        addedge(y,x);
    }
    for(rg int i=1;i<=n;++i)
        read(w[i]);
    dfs1(1,0);
    dfs2(1,1);
    for(rg int i=1;i<=m;++i)
    {
        read(Q[i].s);read(Q[i].t);
        Q[i].lca=lca(Q[i].s,Q[i].t);
//      cerr<<i<<" lca="<<Q[i].lca<<endl;
    }

    for(rg int i=1;i<=n;++i)
        t[i]=w[i]+dep[i];
    for(rg int i=1,now;i<=m;++i)
    {
        now=dep[Q[i].s];
        ql=dfn[Q[i].s],v=1;
        T.add(root[now],1,n);
        ql=dfn[fa[Q[i].lca]],v=-1; // 此处计算lca
        if(ql) // edit 2:加0会加到1上
            T.add(root[now],1,n);
    }
    for(rg int i=1;i<=n;++i)
    {
        ql=dfn[i],qr=dfn[i]+siz[i]-1;
        ans[i]+=T.qsum(root[t[i]],1,n);
//      cerr<<i<<" ans="<<ans[i]<<endl;
    }

    init();
    for(rg int i=1;i<=n;++i)
        t[i]=w[i]-dep[i]+n+1;
    for(rg int i=1,now;i<=m;++i)
    {
        now=dep[Q[i].s]-2*dep[Q[i].lca]+n+1;
        ql=dfn[Q[i].t],v=1;
        T.add(root[now],1,n);
        ql=dfn[Q[i].lca],v=-1; // 此处不计算lca
        T.add(root[now],1,n);
    }
    for(rg int i=1;i<=n;++i)
    {
        ql=dfn[i],qr=dfn[i]+siz[i]-1;
        ans[i]+=T.qsum(root[t[i]],1,n);
//      cerr<<i<<" ans="<<ans[i]<<endl;
    }
    for(rg int i=1;i<=n;++i)
        printf("%d ",ans[i]);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

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

  1. 【LG1600】[NOIP2016]天天爱跑步

    [LG1600][NOIP2016]天天爱跑步 题面 洛谷 题解 考虑一条路径\(S\rightarrow T\)是如何给一个观测点\(x\)造成贡献的, 一种是从\(x\)的子树内出来,另外一种是从 ...

  2. UOJ261 【NOIP2016】天天爱跑步

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  3. BZOJ4719 [Noip2016]天天爱跑步

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  4. noip2016天天爱跑步

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

  5. bzoj 4719: [Noip2016]天天爱跑步

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

  6. [NOIP]2016天天爱跑步

    [NOIP]2016天天爱跑步 标签: LCA 树上差分 NOIP Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...

  7. NOIP2016 天天爱跑步 80分暴力

    https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...

  8. [NOIp 2016]天天爱跑步

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

  9. 【NOIP2016】【LCA】【树上差分】【史诗级难度】天天爱跑步

    学弟不是说要出丧题吗>>所以我就研究了1天lca又研究了1天tj然后研究了一天天天爱跑步,终于写了出来.(最后的平均用时为240ms...比学弟快了1倍...) 题意:给你颗树,然后有m个 ...

随机推荐

  1. SpringBoot导入excle文件数据

    本文主要描述,Springboot框架下上传excel,处理里面相关数据做逻辑分析,由于用到的是前后端分离技术,这里记录的主要是后端java部分,通过与前端接口进行对接实现功能 1.在pom.xml文 ...

  2. spojPlay on Words

    题意:给出几个词语,问能不能接龙. 一开始猜只要所有字母连通,并且只有一个字母出现在开头次数为奇,一个字母末尾为奇,其它偶,就行.后来发现全为偶也行.而且条件也不对,比如ac,ac,ac就不行.实际上 ...

  3. python-day43--单表查询之关键字执行优先级(重点)

    一.关键字的执行优先级(重点) 1.关键字执行优先级 from where #约束条件(在数据产生之前执行) group by #分组 没有分组则默认一组 按照select后的字段取得一张新的虚拟表, ...

  4. TCP-IP详解:Nagle算法

    在使用一些协议通讯的时候,比如Telnet,会有一个字节字节的发送的情景,每次发送一个字节的有用数据,就会产生41个字节长的分组,20个字节的IP Header 和 20个字节的TCP Header, ...

  5. 24.2 网络编程基础——System.Net 命名空间

    使用C#进行网络编程时,通常要用到: System. Net  命名空间. System. Net. Sockets  命名空间. System. Net. Mail  命名空间. 24.2.1 Sy ...

  6. httpclient妙用一 httpclient作为客户端调用soap webservice(转)

    前面有一篇使用HttpClient调用带参数的post接口方法,这里找到一篇使用HttpClient调用Soap协议接口的方式. 原文地址:httpclient妙用一 httpclient作为客户端调 ...

  7. dubbo管理控制台搭建

    1. 从网上下载dubbo管理控制台:dubbo-admin-2.5.4.war 2. 下载tomcat7,解压缩 3. 将tomcat7 webapps/ROOT的文件全部删除,然后把dubbo-a ...

  8. JVM笔记(二) 垃圾收集器(1)

    垃圾收集器 主要通过阅读<深入了解Java虚拟机>(周志明 著)和网络资源汇集而成,为本人学习JVM的笔记.同时,本文理论基于JDK 1.7版本,暂不考虑 1.8和1.9 的新特性,但可能 ...

  9. 深入理解BootStrap Item1-- 列表组(list-group)

    class=”pull-right”:右对齐下拉菜单 list-group-item:列表组,控制列表,以及添加列表徽章 1.列表组 列表组是Bootstrap框架新增的一个组件,可以用来制作列表清单 ...

  10. PHP:第一章——php中数据类型和强制类型转换

    <?php //PHP中的数据类型: //标量类型:布尔型(boolean).整型(integer).浮点型(float).字符串型(string) //复合类型:数组(array).对象(ob ...