环境引入:

  在一个大型的教育官网,会拥有大量优质的视频教程,并且免费提供给用户去下载,文件太多如果高效存储?用户访问量大如何保证下载速度?分布式文件系统是解决这些问题的有效方法之一

一、什么是文件系统

  分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。分布式文件系统的设计基于客户机/服务器模式。一个典型的网络可能包括多个供多用户访问的服务器。另外,对等特性允许一些系统扮演客户机和服务器的双重角色。例如,用户可以“发表”一个允许其他客户机访问的目录,一旦被访问,这个目录对客户机来说就像使用本地驱动器一样。

                                                                     -----------------百度百科

为什么需要:以前,我们将上传的视屏文件等放在一台宿主机内,如果一个盘符内存不够,就增加硬盘个数,但是单纯的增加硬盘个数已经无法满足当代的需求,毕竟硬盘访问速度有限

解决方式:增加计算机个数,将视屏分别放在不同计算机内,通过网络将一个一个计算机的文件系统连接起来组成一个网络文件系统,形成一个分布式网络

优点:用于扩容、高并发场景

    1、一台计算机的文件系统处理能力扩充到多台计算机内同时处理

    2、一台计算机挂了还有另外副本计算提供数据

    3、每台计算机可以放在不同的地域,这样用户就可以就近访问,提高访问速度

二、分布式文件服务提供商

  1、阿里的OSS

   2、七牛云存储

   3、百度云储存

三、什么是fastDFS

  FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

                                                                                 -----百度百科

                图片来源于百度百科

四、fastdfs安装:

  1、安装编译环境

[root@bogon ~]# docker exec -it centos /bin/bash
[root@0b5933e7fd96 /]# yum -y groupinstall 'Development Tools'
[root@0b5933e7fd96 /]# yum -y install wget

  2、下载安装libfastcommon

[root@0b5933e7fd96 /]#git clone https://github.com/happyfish100/libfastcommon.git
[root@0b5933e7fd96 /]#cd libfastcommon/
[root@0b5933e7fd96 /]#./make.sh
[root@0b5933e7fd96 /]#./make.sh install

  3、下载安装fastdfs

[root@0b5933e7fd96 /]#wget https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz
[root@0b5933e7fd96 /]#tar -zxvf V5..tar.gz
[root@0b5933e7fd96 /]#cd fastdfs-5.05/
[root@0b5933e7fd96 /]#./make.sh
[root@0b5933e7fd96 /]#./make.sh install

  4、修改tracker与storage配置文件命名

     备份tracker与storage配置文件,为了防止数据文件的破坏

[root@0b5933e7fd96 /]# find / -name fdfs
/etc/fdfs
[root@0b5933e7fd96 fdfs]# ll
total
-rw-r--r--. root root Jan : client.conf.sample
-rw-r--r--. root root Jan : storage.conf.sample
-rw-r--r--. root root Jan : tracker.conf.sample
[root@0b5933e7fd96 fdfs]# cp client.conf.sample client.conf
[root@0b5933e7fd96 fdfs]#cp storage.conf.sample storage.conf
[root@0b5933e7fd96 fdfs]#cp tracker.conf.sample tracker.conf
[root@0b5933e7fd96 fdfs]# ll
total
-rw-r--r--. root root Jan : client.conf
-rw-r--r--. root root Jan : client.conf.sample
-rw-r--r--. root root Jan : storage.conf
-rw-r--r--. root root Jan : storage.conf.sample
-rw-r--r--. root root Jan : tracker.conf
-rw-r--r--. root root Jan : tracker.conf.sample

  5、配置tracker

[root@0b5933e7fd96 fdfs]# vi tracker.conf
disabled=false
port=
base_path=/home/fastdfs/tracker
http.server_port=

  7、配置storage

disabled=false
group_name=group1
port=
base_path=/home/fastdfs/storage
store_path0=/home/fastdfs/storage-data
tracker_server=192.168.174.128:
http.server_port=

  8、配置路径

[root@0b5933e7fd96 home]# ll
total
drwxr-xr-x. root root Jan : fastdfs
[root@0b5933e7fd96 home]# cd fastdfs/
[root@0b5933e7fd96 fastdfs]# ll
total
drwxr-xr-x. root root Jan : storage
drwxr-xr-x. root root Jan : storage-data
drwxr-xr-x. root root Jan : tracker

  8、启动tracker和storage

[root@0b5933e7fd96 fdfs]# /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
[root@0b5933e7fd96 fdfs]# /usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart
[root@0b5933e7fd96 storage-data]# ps -ef | grep fdfs

五、构建JAVA Client API

github访问地址:https://github.com/happyfish100/fastdfs-client-java

搭建环境

1、创建一个maven工程

2、添加依赖

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<groupId>cn.ibo</groupId>
<artifactId>fastdfs</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>net.oschina.zcx7878</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>

3、新增配置文件fastdfs-client.properties

## fastdfs-client.properties

fastdfs.connect_timeout_in_seconds =
fastdfs.network_timeout_in_seconds = fastdfs.charset = UTF- fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = fastdfs.tracker_servers = 192.168.174.128:

4、编写测试类

  4.1) 上传

  需求:将window 盘符下的指定文件通过fastFDS上传到linux指定目录下

/**
* Created by 佳先森 on 2019/1/13.
* 在此文件中通过fastDSF的client代码访问tracker和storage
* 通过client的api代码访问tracker和storage,他们中间走的socket协议
*/
public class TestFastDFS {
// 测试文件上传
@Test
public void testUpload(){
//通过fastDSF的client代码访问tracker和storage
String local_filename = "77.jpg";//上传文件名
try {
//加载fastDFS客户端的配置文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset); //创建tracker的客户端
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
//定义storage的客户端
StorageClient1 client = new StorageClient1(trackerServer, storageServer);
//文件元数据(如文件名称大小等)
NameValuePair[] metaList = new NameValuePair[];
metaList[] = new NameValuePair("fileName",local_filename);//这是个数组,可以继续添加
//执行上传
String fileId = client.upload_file1("E:\\壁纸\\77.jpg", "jpg", metaList);
System.out.println("upload success. file id is: " + fileId);
//关闭trackerServer的连接
trackerServer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

验证:此时在storage-data目录下可以看到上传的文件

[root@bogon ]# pwd
/home/fastdfs/storage-data/data//
[root@bogon ]# ll
-rw-r--r--. root root 1月 : wKiugFw7OeSAMlI9AADYDjkgjlY905.jpg

4.2)  检索

  根据控制台打印的信息,利用文件ID检索文件信息

//查询上传的文件
@Test
public void testSearch(){
try {
//加载fastDFS客户端的配置文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset); //创建tracker的客户端
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
//定义storage的客户端
StorageClient1 client = new StorageClient1(trackerServer, storageServer);
FileInfo group1 = client.query_file_info("group1", "M00/00/00/wKiugFw7OeSAMlI9AADYDjkgjlY905.jpg");
FileInfo fileInfo = client.query_file_info1("group1/M00/00/00/wKiugFw7OeSAMlI9AADYDjkgjlY905.jpg");
System.out.println(group1);
System.out.println(fileInfo);
//查询文件元信息
NameValuePair[] metadata1 = client.get_metadata1("group1/M00/00/00/wKiugFw7OeSAMlI9AADYDjkgjlY905.jpg");
for(NameValuePair temp:metadata1){
System.out.print(temp.getName()+"\t"+temp.getValue());
}
//关闭trackerServer的连接
trackerServer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}

4.3) 下载文件

  根据文件ID下载文件到指定目录

@Test
public void downLoad(){
try {
//加载fastDFS客户端的配置文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset); //创建tracker的客户端
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
//定义storage的客户端
StorageClient1 client = new StorageClient1(trackerServer, storageServer);
//下载
byte[] bytes = client.download_file1("group1/M00/00/00/wKiugFw7OeSAMlI9AADYDjkgjlY905.jpg");
File file = new File("e:/a.jpg");
FileOutputStream fos = new FileOutputStream(file);
fos.write(bytes);
fos.close();
//关闭trackerServer的连接
trackerServer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}

六、文件服务案列

  先将文件存放到临时目录,再通过tracker server将临时文件上传到fastdfs中的storage中

注意:得先安装fastdfs-nginx-module,再安装nginx,在编译nginx过程中添加fastdfs-nginx-module,顺序弄反,会报

[emerg] unknown directive "ngx_fastdfs_module" ngix整合fastdfs启动后报错

  FastDFS通过Tracker服务器,将文件放在Storage服务器存储,但是同组存储服务器之间需要进入文件复制,有同步延迟的问题。假设Tracker服务器将文件上传到了192.168.4.125,上传成功后文件ID已经返回给客户端。此时FastDFS存储集群机制会将这个文件同步到同组存储192.168.4.126,在文件还没有复制完成的情况下,客户端如果用这个文件ID在192.168.4.126上取文件,就会出现文件无法访问的错误。而fastdfs-nginx-module可以重定向文件连接到源服务器取文件,避免客户端由于复制延迟导致的文件无法访问错误。

1、安装fastdfs-nginx-module

参考博客:https://blog.csdn.net/u010098331/article/details/51646921

[root@bogon local]# wget https://sourceforge.net/projects/fastdfs/files/FastDFS%20Nginx%20Module%20Source%20Code/fastdfs-nginx-module_v1.16.tar.gz
[root@bogon local]# tar xf fastdfs-nginx-module_v1..tar.gz
[root@bogon local]# cd fastdfs-nginx-module/src/
[root@bogon local]# vim config
#编辑config文件,执行如下命令进行批量替换并保存退出,目的:去掉local前缀,指定正确路径目录
:%s+/usr/local/+/usr/+g
[root@bogon src]# pwd
/usr/local/fastdfs-nginx-module/src
[root@bogon src]# cp mod_fastdfs.conf /etc/fdfs
[root@bogon local]# cd /etc/fdfs
[root@bogon fdfs]# vim mod_fastdfs.conf
#修改内容如下:
connect_timeout=
base_path=/tmp(默认为/tmp)
tracker_server=192.168.174.128:
storage_server_port=(默认配置为23000)
url_have_group_name = true
store_path0=/home/fastdfs/storage-data
group_name=group1(默认配置为group1)
[root@bogon fastdfs-5.05]# pwd
/usr/java/fastdfs-5.05
[root@bogon fastdfs-5.05]# cd conf
[root@bogon conf]# cp http.conf /etc/fdfs
[root@bogon conf]# cp mime.types /etc/fdfs

安装nginx

[root@bogon local]# tar -zxvf nginx-1.6.
[root@bogon local]# cd nginx-1.6./
[root@bogon nginx-1.6.]#
./configure --prefix=/usr/local/nginx --add-module=/usr/local/fastdfs-nginx-module/src
[root@bogon nginx-1.6.]#make && make install
[root@bogon local]# cd nginx
[root@bogon nginx]# cd conf
[root@bogon conf]# vim nginx.conf
 location /group1/M00 {
root /home/fastdfs/storage-data;
ngx_fastdfs_module;
}
[root@bogon conf]# cd ..
[root@bogon nginx]# cd sbin/
[root@bogon sbin]# ./nginx
ngx_http_fastdfs_set pid=

配置nginx:

server {
listen ;
server_name localhost; #charset koi8-r; #access_log logs/host.access.log main;
location /group1/M00 {
root /home/fastdfs/storage-data/data; #storage_path0
ngx_fastdfs_module;             #虚拟模块
}
}

此时根据刚刚测试类中上传的文件利用nginx访问:如果nginx能够正常访问表示配置nginx成功

这是通过http的方式(集成nginx)访问上传图片

七、搭建文件管理服务

  文件管理服务提供通过http方式上传文件、删除文件、查询文件的功能,管理员通过文件管理服务队文件服务器上的文件进行管理

  文件管理服务采用Spring Boot开发,文件管理服务通过与fastDFS交互最终将用户上传的文件存储到fastDFS上

1、建立实体类

/**
* Created by 佳先森 on 2019/1/13.
*/
public class FileSystem {
private String fileId;
private String filePath;
private long fileSize;
private String fileName;
private String fileType;
//省去set/get
}

2、编写配置文件application.yml

server:
port: fastdfs:
#文件上传临时目录
upload_location: E:\\download\\

3、建立controller

/**
* Created by 佳先森 on 2019/1/13.
*/
@RestController
@RequestMapping("/filesystem")
public class FileServerController { @Value("${fastdfs.upload_location}") //读取配置文件
private String upload_location; @PostMapping("/upload")
@ResponseBody
public FileSystem upload(@RequestParam("file") MultipartFile file) throws IOException {
//先将文件存储在web服务器上(本机),再使用fastDFS的client将文件到fastDFS服务器
FileSystem fileSystem = new FileSystem();
//得到文件的原始名称
String originalFilename = file.getOriginalFilename();
String extention = originalFilename.substring(originalFilename.lastIndexOf("."));
//重构上传文件名
String newFileName = UUID.randomUUID()+extention;
//定义file,使用file存储上传的文件
File file1 =new File(upload_location+newFileName);
file.transferTo(file1);
//获取新上传文件的物理路径
String newFilePath = file1.getAbsolutePath();
try {
//加载fastDFS客户端的配置文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset); //创建tracker的客户端
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
//定义storage的客户端
StorageClient1 client = new StorageClient1(trackerServer, storageServer);
//文件元数据(如文件名称大小等)
NameValuePair[] metaList = new NameValuePair[];
metaList[] = new NameValuePair("fileName",originalFilename);//这是个数组,可以继续添加
//执行上传,将上传成功的存放在web服务器(本机)上的文件上传到fastDFS
String fileId = client.upload_file1(newFilePath, extention, metaList);
System.out.println("upload success. file id is: " + fileId);
fileSystem.setFileId(fileId);
fileSystem.setFilePath(fileId);
fileSystem.setFileName(originalFilename); //通过调用service即dao将文件路径存储到数据库中
//....todo //关闭trackerServer的连接
trackerServer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
return fileSystem;
}
}

4、编写启动类

/**
* Created by 佳先森 on 2019/1/13.
*/
@SpringBootApplication
public class FileServiceApplication {
public static void main(String[] args) {
SpringApplication.run(FileServiceApplication.class);
}
}

5、编写前端界面

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Upload</title>
</head>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <body>
<div id="clj">
<el-upload
action=""
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</div>
<script type="text/javascript" src="vue.min.js"></script>
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script>
new Vue({
el: '#clj',
data: {
dialogVisible: false,
dialogImageUrl: ''
},

      methods: {
        handlePictureCardPreview(file){      #预览
        this.dialogImageUrl ="http://192.168.174.128/"+file.response.filePath   #注意:预览时访问的图片地址是通过nginx代理的,需要配置图片所在宿主机地址  
        this.dialogVisible = true;
      },
        handleRemove(){}
      }

    })
</script>
</body>
</html>

6、nginx中配置页面访问路径

#图片服务测试(图片页面)
server {
listen ;
server_name localhost;
location / {
root /usr/java/javademo/springboot-vue-fastdfs/upload/;
index index.html;
}
}

此时访问http://192.168.174.128:7283/upload.html,若成功访问到页面,则配置成功

但是这样远远不够的,因为页面中的action配置的请求后台的action是访问不到的,存在跨域问题(页面与后端代码不在同一台宿主机上),解决跨域问题常见的思路就是在nginx中配置代理

 #图片服务测试(图片页面)
server {
listen ;
server_name localhost; #这里配置的是页面所在宿主机ip
location / {
root /usr/java/javademo/springboot-vue-fastdfs/upload/;
index index.html;
}
location ^~ /filesystem/ { #配置代理
proxy_pass http://192.168.2.174:22100/filesystem/; #注意这里配置的是后端代码所在宿主机ip
}
}

此时上传和预览功能已经完成

克隆源码地址:git@gitee.com:MR_JiaXianSen/FastDFS.git

分布式文件系统之FastDFS的更多相关文章

  1. 分布式文件系统服务器FastDFS

    1. 什么是FastDFS FastDFS 是用 c 语言编写的一款开源的分布式文件系统.FastDFS 为互联网量身定制, 充分考虑了冗余备份.负载均衡.线性扩容等机制,并注重高可用.高性能等指标, ...

  2. 分布式文件系统及FastDFS

    1.前言 今天来谈谈分布式文件系统,侧重点是文件系统,分布式稍微带一下.然后聊下我用的FastDFS的例子. 2.从小需求开始 我的博客的编辑器用的是markdown,它内嵌了一个文件上传功能,不过后 ...

  3. 从入门到精通(分布式文件系统架构)-FastDFS,FastDFS-Nginx整合,合并存储,存储缩略图,图片压缩,Java客户端

    导读 互联网环境中的文件如何存储? 不能存本地应用服务器 NFS(采用mount挂载) HDFS(适合大文件) FastDFS(强力推荐

  4. 分布式文件系统之FastDFS安装部署

    前面我们了解了分布式文件系统mogilefs的框架以及安装部署和简单使用,回顾请参考https://www.cnblogs.com/qiuhom-1874/tag/MogileFS/:今天我们来了解下 ...

  5. 分布式文件系统之 FastDFS

    FastDFS 百度百科 FastDFS 是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.特别适合 ...

  6. FastDFS 分布式文件系统

    1       学习目标 了解项目中使用FastDFS的原因和意义. 掌握FastDFS的架构组成部分,能说出tracker和storage的作用. 了解FastDFS+nginx上传和下载的执行流程 ...

  7. FastDFS分布式⽂文件系统

    FastDFS分布式⽂文件系统  1. 什么是FastDFS FastDFS 是⽤用 c 语⾔言编写的⼀一款开源的分布式⽂文件系统.FastDFS 为互联⽹网量量身定制, 充分考虑了了冗余备份.负载均 ...

  8. 第三方-FastDFS分布式文件系统

    1.什么是FastDFS? FastDFS 是用 c 语言编写的一款开源的分布式文件系统.FastDFS 为互联网量身定制, 充分考虑了冗余备份.负载均衡.线性扩容等机制,并注重高可用.高性能等指标, ...

  9. FastDFS图片服务器(分布式文件系统)学习。

    参考:https://blog.csdn.net/hiqingtian/article/details/79413471 https://blog.csdn.net/sinat_40399893/ar ...

随机推荐

  1. HAproxy-1.6.3 安装部署

    反向代理优缺点: haproxy反向代理高性能的HTTP,TCP反向代理 nginx:优点:1.web服务器,比较广泛2.工作7层location设置比较复杂基于HTTP(url,cookies,ag ...

  2. win7 + eclipse + cocos2dx 开发环境配置

    最近想在win7上配置eclipse+cocos2dx开发环境,在安装之前一定要注意每项是32位还是64位,我选择的都是64位版本的,闲话少叙我们开始安装吧! 1.下载cocos2dx,我选择的是co ...

  3. jekyll Mac上各种安装问题总结

    Mac上自带了ruby,版本信息如下: qiyongdeMacBook-Air:webproxy qiyong$ ruby -v ruby 2.0.0p481 (2014-05-08 revision ...

  4. IE6,7,8在boostrap中兼容h5和css3

    IE6.7.8版本(IE9以下版本)浏览器兼容html5新增的标签,引入下面代码文件即可: <script src="https://oss.maxcdn.com/libs/html5 ...

  5. 手把手教你看KEGG通路图!

    手把手教你看KEGG通路图! 亲爱的小伙伴们,是不是正关注代谢通路研究?或者你正面对数据,绞尽脑汁?小编当然不能让亲们这么辛苦,今天就跟大家分享KEGG代谢通路图的正确解读方法,还在迷糊中的小伙伴赶紧 ...

  6. 3.3.7 跳表 SkipList

    一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下,ConcurrentHashMap 存取速度是ConcurrentSki ...

  7. Typora的图片根目录设置,

    需求:使Typora的图片,设置到指定的文件里. 方便上传与转移. 步骤: 1 位置: 编辑 ->图片工具->设置图片根目录. 2 .Preference -> Editor -&g ...

  8. 设计模式23:Visitor 访问者模式(行为型模式)

    Visitor 访问者模式(行为型模式) 动机(Motivation)在软件构造过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的修改,将会给子类带来繁重的 ...

  9. 编写高质量代码改善C#程序的157个建议——建议93:构造方法应初始化主要属性和字段

    建议93:构造方法应初始化主要属性和字段 类型的属性应该在构造方法调用完毕前完成初始化工作.如果字段没有在初始化器中设置初始值,那么它就应该在构造方法中初始化. 类型一旦被实例化,那么它就应该被视为具 ...

  10. CodeForces 877E Danil and a Part-time Job(dfs序+线段树)

    Danil decided to earn some money, so he had found a part-time job. The interview have went well, so ...