首页 > 其他分享 >LJT的书库题解

LJT的书库题解

时间:2022-09-30 21:47:52浏览次数:83  
标签:deth 书库 return int 题解 read now LJT getchar

原题链接

题目难度较低,看懂题目后特别好想。

注意到题目中说的,一个藏书室最多与两个相同的藏书室相连。那么含有所需书的藏书室是树上的一条链。
但是,书的本数未知,且链的两段可能会继续向下延伸。
具体数量无法确定。

注意到题目是要我们求最小值,那么两个端点是否继续向下连接便不重要了, 而每个藏书库至少会放一本书,所以实际上题目就是要我们求两条路径交集的长度。

task1:

不知道会不会有人写阶乘做法,反正放进去了。

task2: 链

直接用深度计算就好啦。

task3: 菊花图

可以发现,路径重合只会有 \(1, 2, 3\) 三种情况。

所以特判一下 \(a, b, c\) 即可。

task4:

\(n \le 1000, q \le 1000\)。 对于求出两条路径的交集,考虑直接从 \(a\) 和 \(c\) 开始遍历,同时记录数组 \(pre[i]\)。之后,再次遍历两次求出交集大小。

\(25 pts\) 的代码:

#include <bits/stdc++.h>
using namespace std;
#define N 1000010

inline int read(){
    int x = 0, s = 1;
    char c = getchar();
    while(!isdigit(c)){
        if(c == '-')s = -1;
        c = getchar();
    }
    while(isdigit(c)){
        x = x * 10 + (c ^ '0');
        c = getchar();
    }
    return x * s;
}

struct node{
    int v, next;
} t[N << 1];
int f[N];

int bian = 0;
inline void add(int u, int v){
    t[++bian] = (node){v, f[u]}, f[u] = bian;
    t[++bian] = (node){u, f[v]}, f[v] = bian;
    return ;
}

bool vis[N], hav[N];
int ans = 0; 
int pre[N]; 
int fa[N]; 

void dfs1(int now, int father){  // 打上标记  
	pre[now] = father; 
	for(int i = f[now]; i; i = t[i].next){
		int v = t[i].v;
		if(v == father) continue; 
		dfs1(v, now); 
	}
	return ; 
}

void dfs2(int now, int father){
	fa[now] = father;
	for(int i = f[now]; i; i = t[i].next){
		int v = t[i].v;
		if(v != father){
			dfs2(v, now); 
		}
	}
	return ; 
}

int main(){
    int n = read(), T = read(), num = read();
    for(int i = 1;i < n; i++){
        int x = read(), y = read();
        add(x, y);
    }
    while(T--){
    	int a = read(), b = read(), c = read();
		memset(vis, 0, sizeof(vis)); 
		memset(pre, 0, sizeof(hav)); 
		memset(hav, 0, sizeof(hav)); 
		memset(fa, 0, sizeof(fa)); 
		ans = 0; 
		pre[a] = a; 
		dfs1(a, a); 
		int x = b;
		while(x != a && x){
			hav[x] = 1;
			x = pre[x]; 
		}
		hav[a] = 1; 
		dfs2(b, b); 
		x = c;
		while(x != b && x){
			if(hav[x]) ans++;
			x = fa[x]; 
		}
		if(hav[b]) ans++; 
		cout << ans << endl; 
    }
    return 0;
}

满分做法:

\(n \le 1000\) 的做法的弊端在于求交集太慢。其实我们直接求 \(LCA\) 然后用深度计算长度就好啦!

树链剖分模板:
(本来想着卡下倍增常数,怕被骂太毒瘤就算了。)

#include <bits/stdc++.h>
using namespace std;
#define N 1000010

inline int read(){
    int x = 0, s = 1;
    char c = getchar();
    while(!isdigit(c)){
        if(c == '-')s = -1;
        c = getchar();
    }
    while(isdigit(c)){
        x = x * 10 + (c ^ '0');
        c = getchar();
    }
    return x * s;
}

struct node{
    int v, next;
} t[N << 1];
int f[N];

int bian = 0;
inline void add(int u, int v){
    t[++bian] = (node){v, f[u]}, f[u] = bian;
    t[++bian] = (node){u, f[v]}, f[v] = bian;
    return ;
}

int deth[N], siz[N], son[N], fa[N], top[N]; 

#define v t[i].v
void dfs1(int now, int father){
    siz[now] = 1;
    fa[now] = father;
    deth[now] = deth[father] + 1;
    for(int i = f[now]; i; i = t[i].next){
        if(v != father){
            dfs1(v, now);
            siz[now] += siz[v];
            if(siz[v] > siz[son[now]])
                son[now] = v;
        }
    }
    return ;
}

void dfs2(int now, int tp){
    top[now] = tp;
    if(!son[now]) return ;
    dfs2(son[now], tp);
    for(int i = f[now]; i; i = t[i].next){
        if(v != fa[now] && v != son[now])
            dfs2(v, v);
    }
    return ;
}

int lca(int x, int y){
    while(top[x] != top[y]){
        if(deth[top[x]] < deth[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    return deth[x] > deth[y] ? y : x;
} 


#undef v

int main(){
    int n = read(), T = read(), num = read();
    for(int i = 1;i < n; i++){
        int x = read(), y = read();
        add(x, y);
    }
    dfs1(1, 0);
    dfs2(1, 0);
    while(T--){
        int a = read(), b = read(), c = read();
        int ans1 = abs(2 * deth[lca(a, b)] - deth[b] - deth[a]);
        int ans2 = abs(2 * deth[lca(a, c)] - deth[a] - deth[c]);
        int ans3 = abs(2 * deth[lca(b, c)] - deth[b] - deth[c]);
    	printf("%d\n", (ans1  + ans3 - ans2) / 2 + 1);
    }
    return 0;
}

标签:deth,书库,return,int,题解,read,now,LJT,getchar
From: https://www.cnblogs.com/wondering-world/p/16746324.html

相关文章

  • 【Azure 应用服务】本地Node.js部署上云(Azure App Service for Linux)遇到的三个问题
    问题描述当本地Node.js(Linux+Node.js+npm+yarn)部署上云,选择AzureAppServiceforLinux环境。但是在部署时,遇见了以下三个问题:问题一:使用VSCode进行部署,部署速......
  • CF600C题解
    题意有一串字符串\(S\),设改变\(S\)中的任意一个字符称为1次转变(交换任意2个字符不算转变次数),求在操作最少的情况下可得到的回文字符串正文♦算法:找规律♦准备......
  • 题解 [POI2010]ZAB-Frog
    很厉害的题。倍增和单调队列。这是zpl新手向算法第二弹,第一弹可以看小挖的核燃料填充我会尽量讲的比较细致。同第一弹,尽量配合代码食用。这道题的题目描述写的不是......
  • useState"失效“问题解释和解决方案
    示例:const[count,setCount]=useState(0)简单的onclick事件中,setCount(1)后紧接着输出或者使用,则输出的值还是0原因:setState会导致页面刷新,(useRef不会)页面刷新的时候......
  • 【题解】P2167 [SDOI2009]Bill的挑战(状压 DP)
    【题解】P2167[SDOI2009]Bill的挑战挺好的一道状压DP。可惜我脑子有病。()题目链接P2167[SDOI2009]Bill的挑战](https://www.luogu.com.cn/problem/P3225)题意概述......
  • 13.56M系列芯片-SI522/SI522A/SI523/ FMI7522 /FMI7550 /RC522芯片常见问题解答
    13.56M系列芯片-标配版:SI522/SI522A/SI523的几款芯片会遇到的一些常见问题解答:SI522和SI522A的异同点?SI522A为SI522的升级版本,SI522A增加了ACD工作模式,其他均相同。标配......
  • LG4381 [IOI2008] Island 题解
    LG4381[IOI2008]Island给定一个基环树森林,求每棵基环树的直径长度和。直径是基环树上最长的一条简单路径。题目保证树边的方向构成了一颗内向树。题解先简单说一下......
  • -bash: ./start.sh: /bin/bash^M: bad interpreter问题解决
    出现上面错误的原因是脚本文件是DOS格式,即每一行的行尾以\r\n来标识,使用vim打开脚本,运行::setff?显示fileformat=dos,就是说格式不兼容,在Unix下运行脚本会提示该错误。......
  • 关于multi-statement not allow问题解决
    出现这个问题是因为druid有一个防火墙,默认是不允许批量操作的,目的应该是防止sql注入等风险。如果你在url中设置了allowMultiQueries=true允许批量操作。那么你的配置应该......
  • Redis(六)应用问题解决
    第一章缓存穿透1.1问题描述key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用......