首页 > 其他分享 >accoders NOI #5014. 树上询问(query) 题解

accoders NOI #5014. 树上询问(query) 题解

时间:2022-10-21 14:25:16浏览次数:47  
标签:5014 NOI dep 题解 int MAXN lca qTo query

昨天刚刚做过一道类似的题,没想到在模拟赛当中出现了。

题目描述

有一棵 \(n\) 个结点的树,有 \(m\) 次询问,每次询问给你两个整数 \(l,r\),问存在多少个整数 \(k\) 使得从 \(l\) 沿着 \(l\) 到 \(r\) 的简单路径走 \(k\) 步恰好到达 \(k\)。

思路

考虑将一条 \(l\) 到 \(r\) 的路径拆成 \(l\) 到 \(lca\) 和 \(lca\) 到 \(r\)。

设 \(dep_x\) 表示结点 \(x\) 的深度,\(l\) 到 \(lca\) 的贡献就是 \(\sum_{x\in[l,lca]}[dep_l-dep_x=x]=\sum_{x\in[l,lca]}[dep_l=x+dep_x]\),\(lca\) 到 \(r\) 的答案是 \(\sum_{y\in[lca,r]}[dep_r-dep_y=len-y]=\sum_{y\in[lca,r]}[dep_r-len=dep_y-y]\)

对于 \(l\) 到 \(lca\) 路径上,\(dep_l\) 为定值,那么运用树上差分的思想,可以将 \(root\) 到 \(l\) 路径上的答案减去 \(root\) 到 \(lca\) 路径上的答案得到。\(lca\) 到 \(r\) 路径上同理。

Code

/*
 * Title: 267C. 树上询问(query)
 * Source: accoders NOI-2022NOIP A层联测12
 * URL: http://47.92.197.167:5283/contest/267/problem/3
 * Author: Steven_lzx
 * Command: -std=c++14 -O2 -lm -Wall -fno-ms-extensions
 * Date: 2022.10.21
 */
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 300005
int n,m,x,y,z,l[MAXN],r[MAXN],c[MAXN],dep[MAXN],t[MAXN<<1],f[MAXN][21],pre[MAXN],suf[MAXN],tot,len,now,ans[MAXN];
int nxt[MAXN<<1],head[MAXN],to[MAXN<<1],cnt,qTo[MAXN<<1],w[MAXN<<1],qNxt[MAXN<<1],qHead[MAXN];
namespace FASTIO
{
    inline int read()
    {
        int res=0,f=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            res=res*10+ch-'0';
            ch=getchar();
        }
        return res*f;
    }
    void write(int x)
    {
        int top=0;
        char st[25];
        do 
        {
            st[++top]=x%10+'0';
            x/=10;
        }
        while(x);
        while(top)
            putchar(st[top--]);
        return;
    }
}
using namespace FASTIO;
namespace GRAPH
{
    inline void addEdge(const int &x,const int &y)
    {
        nxt[++tot]=head[x];
        head[x]=tot;
        to[tot]=y;
        return;
    }
    void DFS1(const int &u,const int &fa)
    {
        int v;
        f[u][0]=fa;
        dep[u]=dep[fa]+1;
        t[dep[u]+u]++;
        pre[u]=t[dep[u]];
        for(register int i=head[u];i;i=nxt[i])
        {
            v=to[i];
            if(v==fa)
                continue;
            DFS1(v,u);
        }
        t[dep[u]+u]--;
        return;
    }
    inline int lca(int x,int y)
    {
        if(dep[x]<dep[y])
            swap(x,y);
        for(register int i=19;~i;i--)
            if(dep[f[x][i]]>=dep[y])
                x=f[x][i];
        if(x==y)
            return x;
        for(register int i=19;~i;i--)
        {
            if(f[x][i]!=f[y][i])
            {
                x=f[x][i];
                y=f[y][i];
            }
        }
        return f[x][0];
    }
    void insEdge(int x,int id,int len)
    {
        qNxt[++cnt]=qHead[x];
        qHead[x]=cnt;
        qTo[cnt]=id;
        w[cnt]=len;
        return;
    }
    void DFS2(int x,int y,int op)
    {
        (op)?t[dep[x]+x]++:t[dep[x]-x+n]++;
        for(register int i=qHead[x];i;i=qNxt[i])
        {
            now=((op)?t[w[i]]:t[dep[r[qTo[i]>m?qTo[i]-m:qTo[i]]]-w[i]+n]);
            if(qTo[i]>m)
                ans[qTo[i]-m]-=now;
            else
                ans[qTo[i]]+=now;
        }
        for(register int i=head[x];i;i=nxt[i])
            if(to[i]!=y)
                DFS2(to[i],x,op);
        (op)?t[dep[x]+x]--:t[dep[x]-x+n]--;
        return;
    }
}
using namespace GRAPH;
int main()
{
	freopen("query.in","r",stdin);
	freopen("query.out","w",stdout);
	n=read();
    m=read();
	for(register int i=1;i<n;i++)
    {
		x=read();
        y=read();
		addEdge(x,y);
        addEdge(y,x);
	}
	DFS1(1,0);
	for(register int j=1;j<=19;j++)
        for(register int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
	for(register int i=1;i<=m;i++)
    {
		l[i]=read();
        r[i]=read();
        c[i]=lca(l[i],r[i]);
		ans[i]=pre[l[i]];
		insEdge(r[i],i,dep[l[i]]+dep[r[i]]-2*dep[c[i]]);
		insEdge(c[i],i+m,dep[l[i]]+dep[r[i]]-2*dep[c[i]]);
	}
	DFS2(1,0,0);
	cnt=0;
	memset(qHead,0,sizeof(qHead));
	for(int i=1;i<=m;i++)
        insEdge(f[c[i]][0],i+m,dep[l[i]]);
	DFS2(1,0,1);
	for(register int i=1;i<=m;i++)
    {
        write(ans[i]);
        putchar('\n');
    }
    fclose(stdin);
    fclose(stdout);
	return 0;
}

标签:5014,NOI,dep,题解,int,MAXN,lca,qTo,query
From: https://www.cnblogs.com/2020gyk080/p/16813263.html

相关文章

  • 顺丰科技智慧物流校园技术挑战赛 一份题解
    我只是做了代码裁缝的角色罢了目录​​试题地址​​​​1​​​​2​​​​3​​​​4​​​​5​​试题地址​​https://leetcode.cn/contest/sf-tech/​​1DFS判定有向图......
  • NOIP2014普及组复赛参考解析
    目录P2141[NOIP2014普及组]珠心算测验P2118[NOIP2014普及组]比例简化P2239[NOIP2014普及组]螺旋矩阵P2258[NOIP2014普及组]子矩阵题目传送P2141[NOIP2014......
  • P1850 [NOIP2016 提高组] 换教室
    [NOIP2016提高组]换教室题目描述对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程。在可以选择的课程中,有\(2n\)节课程安排在\(n\)个......
  • 题解 P5527 [Ynoi2012] NOIP2016 人生巅峰
    人生第一道Ynoi,同时也是1k通过。不卡常不难写,小清新Ynoi真的不多见了。前置知识:抽屉原理,树状数组,bitset,动态规划基础。首先考虑一个事实,当这个区间够长是必然有解的......
  • NOIP2015普及组复赛参考解析
    目录P2669[NOIP2015普及组]金币P2670[NOIP2015普及组]扫雷游戏P2671[NOIP2015普及组]求和P2672[NOIP2015普及组]推销员题目传送P2669[NOIP2015普及组]金......
  • NOIP2017 普及组复赛参考解析
    目录P3954[NOIP2017普及组]成绩P3955[NOIP2017普及组]图书管理员P3956[NOIP2017普及组]棋盘P3957[NOIP2017普及组]跳房子题目传送P3954[NOIP2017普及组]......
  • CF645E Intellectual Inquiry 题解
    传送门|无耻地宣传我的博客(矩乘代码在最后)看一眼题,没什么思路,那大概就是个dp了。先求已知序列的方案数。考虑怎么设计状态。因为本质不同,如果设\(f[i]\)表示,......
  • electron升级到20版本后,禁用第三方cookie、跨域问题解决方法
    最近公司的electron项目从13升级到最新的20版本,导致qq登录失效问题,特此记录1.qq扫码登录失效升级后之前的老版本可以扫码登录,但是新版本扫码登录后,页面直接刷新,没有登录......
  • P8251 [NOI Online 2022 提高组] 丹钓战 题解
    本文写于2022-03-2614:45:14。原博客地址题目链接算法(倍增)$O((n+q)\logn)$为简便,把元素$(a_i,b_i)$称为元素$i$。对一个区间$[l,r]$模拟一遍,从空栈开始,头......
  • [NOIP2014 提高组] 联合权值 dfs+技巧
    题意树上每个结点的权值为\(w_i\),若点\(i\)和点\(j\)满足:\(i\)和\(j\)的最短距离为2,则会产生$w_i*w_j$的联合权值。求最大联合权值和联合权值之和。分析①最大联合......