当前位置: 首页 > news >正文

天天爱跑步NOIP

首先,我们考虑对于一条路径



从x->y,可以把它拆分成两部分,图中用虚线分开,然后这条路径就变成了x->lca,son[lca]->y

先来考虑从x向上走到lca的路径,对于这条路上的节点i,玩家能对节点i产生贡献的前提是deep[x]-w[i]=deep[i]

移项可得deep[x]=w[i]+deep[i],也就是说起点在w[i]+deep[i]这个深度的玩家向上走的时候都会对节点i产生1的贡献,(玩家想对节点i产生贡献,那它的深度一定等于w[i]+deep[i])

对于每一层深度建一颗线段树,动态开点,先dfs整个树,求出每个节点的dfs序,那么这就转化成区间问题,对于每一个玩家s->t,在深度为deep[s]的线段树id[s]的位置加1,id[fa[lca(s,t)]]-1,利用了差分思想,每一次求一下节点i在深度为w[i]+deep[i]的线段树里[in[i],out[i]]区间和就是答案,利用差分可以防止不合法的计算,id[fa[lca(s,t)]]-1,保证x不会被lca以上的节点计算贡献

然后考虑向下的路径,对于son[lca]->y的路径上的节点j,玩家能对j产生贡献前提是deep[x]+deep[y]-2*deep[lca(x,y)]-w[j]=deep[y]-deep[j]

移项可得deep[x]-2*deep[lca(x,y)]=w[j]-deep[j]相应的,我们在deep[x]-2*deep[lca]深度的线段树id[x]的位置加1,lca处减1,然后对于每个节点,查询w[j]-deep[j]深度的线段树[in[j],out[j]]即可

注意红字部分可能出现负数,下标统一加n

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 300005
using namespace std;
int n,m;
int fa[maxn],d[maxn*5],ans[maxn];
struct edge
{
    int to,ne;  
}b[maxn*2];
int kk=0,head[maxn];
struct edge2
{
    int fr,to,len,anc;  
}s[maxn*2];
int w[maxn];
int f[maxn][35];
inline int read()
{
     int x=0;
     char ch=getchar();
     while(ch<'0'||ch>'9') ch=getchar();
     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     return x;  
}
inline void add(int u,int v)
{
     kk++;
     b[kk].to=v;b[kk].ne=head[u];head[u]=kk; 
}
inline void init()
{
     memset(head,-1,sizeof(head));
     memset(f,-1,sizeof(f));
}
void pre()
{ 
     for(int i=1;i<=n;i++) f[i][0]=fa[i];
     for(int j=1;(1<<j)<=n;j++)
       for(int i=1;i<=n;i++)
       if(f[i][j-1]!=-1) f[i][j]=f[f[i][j-1]][j-1];
}
int lca(int x,int y)
{
    //printf("%d %d\n",x,y);
     if(d[x]<d[y]) swap(x,y);
     int dc=d[x]-d[y];
     for(int i=0;dc;i++)
     if((dc&(1<<i))){
        dc^=(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]&&f[x][i]!=-1){
        x=f[x][i];   y=f[y][i];
     }
     return fa[x];
}
int q[maxn],h[maxn],id=0;
void dfs(int x)
{
     q[x]=++id;
     for(int i=head[x];i!=-1;i=b[i].ne)
     if(b[i].to!=fa[x]){
         fa[b[i].to]=x; d[b[i].to]=d[x]+1;
         dfs(b[i].to);
     }
     h[x]=id;
}
int root[maxn*30],sum[maxn*30],ls[maxn*30],rs[maxn*30];
int cnt=0;
struct Tree
{
    void update(int k)
    {
        sum[k]=sum[ls[k]]+sum[rs[k]]; 
    }
    void insert(int &k,int l,int r,int x,int w)
    {
        if(!x) return ;
        if(!k) k=++cnt;
        sum[k]+=w;
        if(l==r) return ;
        int mid=(l+r)/2;
        if(x<=mid) insert(ls[k],l,mid,x,w);
        else insert(rs[k],mid+1,r,x,w);
        update(k);
    }  
    int quiry(int k,int l,int r,int ll,int rr)
    {
        if(!k) return 0;
        if(ll<=l&&r<=rr) return sum[k];
        int ans=0;
        int mid=(l+r)/2;
        if(ll<=mid) ans+=quiry(ls[k],l,mid,ll,rr);
        if(rr>mid)  ans+=quiry(rs[k],mid+1,r,ll,rr);
        return ans;
    } 
}tr;
inline void init2()
{
    memset(root,0,sizeof(root));
    memset(sum,0,sizeof(sum));
    memset(ls,0,sizeof(ls));
    memset(rs,0,sizeof(rs));
    cnt=0;
}
int main()
{
    freopen("runninga.in","r",stdin);
    freopen("runninga.out","w",stdout);
    init();
    n=read();m=read();
    int x,y,anc;
    for(int i=1;i<n;i++){
        x=read(); y=read();
        add(x,y); add(y,x);
    }
    dfs(1);
    pre();
    for(int i=1;i<=n;i++) w[i]=read();
    for(int i=1;i<=m;i++){
       s[i].fr=read(); s[i].to=read();
       anc=lca(s[i].fr,s[i].to);
       s[i].len=d[s[i].fr]+d[s[i].to]-2*d[anc];
       s[i].anc=anc;
       tr.insert(root[d[s[i].fr]],1,n,q[s[i].fr],1);
       tr.insert(root[d[s[i].fr]],1,n,q[fa[anc]],-1);  
    }
    for(int i=1;i<=n;i++) ans[i]+=tr.quiry(root[w[i]+d[i]],1,n,q[i],h[i]);
    init2();
    for(int i=1;i<=m;i++){
       int t=d[s[i].fr]-(d[s[i].anc]<<1)+(n<<1);
       tr.insert(root[t],1,n,q[s[i].to],1);
       tr.insert(root[t],1,n,q[s[i].anc],-1);
    }
    for(int i=1;i<=n;i++)
      ans[i]+=tr.quiry(root[w[i]-d[i]+(n<<1)],1,n,q[i],h[i]);     
    for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    return 0;
}


转载于:https://www.cnblogs.com/hunterxhunterl/p/7780671.html

相关文章:

  • 白话经典之String字符串详解
  • C++ STL疑惑知识点
  • Python基础
  • 理解浏览器关键的渲染路径
  • Android RecyclerView 水平滚动+自动循环轮播
  • GBDT和随机森林的区别
  • C#使用Xamarin开发可移植移动应用(3.Xamarin.Views控件)附源码
  • 在客户端先通过JS验证后再将表单提交到服务器
  • hihocoder 1320 压缩字符串(字符串+dp)
  • 一元线性回归模型的基本假设
  • marathon小知识点分享之如何远程调试marathon
  • AJAX的get和post请求原生编写方法
  • C/C++ 数据范围
  • Linux操作系统目录和Linux常用的文件和目录管理命令
  • cv2
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • django开发-定时任务的使用
  • es6--symbol
  • miaov-React 最佳入门
  • React Transition Group -- Transition 组件
  • text-decoration与color属性
  • 面试总结JavaScript篇
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 前端代码风格自动化系列(二)之Commitlint
  • 设计模式走一遍---观察者模式
  • Hibernate主键生成策略及选择
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • # include “ “ 和 # include < >两者的区别
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #QT(智能家居界面-界面切换)
  • (04)odoo视图操作
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (LeetCode C++)盛最多水的容器
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (二)Linux——Linux常用指令
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (十三)Flask之特殊装饰器详解
  • (四)鸿鹄云架构一服务注册中心
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)Oracle 9i 数据库设计指引全集(1)
  • ***监测系统的构建(chkrootkit )
  • .FileZilla的使用和主动模式被动模式介绍
  • .htaccess配置重写url引擎
  • .net CHARTING图表控件下载地址
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET关于 跳过SSL中遇到的问题
  • .net解析传过来的xml_DOM4J解析XML文件
  • .NET中使用Redis (二)
  • .Net组件程序设计之线程、并发管理(一)
  • .pop ----remove 删除