《P3038 [USACO11DEC] Grass Planting G》

題目描述

給出一棵有?n?個節點的樹,有?m?個如下所示的操作:

  • 將兩個節點之間的?路徑上的邊?的權值均加一。

  • 查詢兩個節點之間的?那一條邊?的權值,保證兩個節點直接相連。

初始邊權均為 0。

輸入格式

第一行兩個整數?n,m,含義如上。

接下來?n?1?行,每行兩個整數?u,v,表示?u,v?之間有一條邊。

接下來?m?行,每行格式為?op u v,op=P?代表第一個操作,op=Q?代表第二個操作。

輸出格式

若干行。對于每個查詢操作,輸出一行整數,代表查詢的答案。

顯示翻譯

題意翻譯

輸入輸出樣例

輸入 #1復制

4 6 
1 4 
2 4 
3 4 
P 2 3 
P 1 3 
Q 3 4 
P 1 4 
Q 2 4 
Q 1 4 

輸出 #1復制

2 
1 
2 

說明/提示

對于?100%?的數據,2≤n≤105,1≤m≤105。

代碼實現:

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

// 節點數量和操作數量
int nodeCount, operationCount;

// 存儲每個節點的父節點
int parentOfNode[100001];?
// 存儲每個節點在樹中的深度
int depthOfNode[100001];?
// 存儲每個節點的重兒子節點
int heavySonOfNode[100001];?
// 存儲以每個節點為根的子樹的節點數量
int subtreeNodeCount[100001];?
// 存儲每個節點所在重鏈的頂端節點
int topNodeOfChain[100001];?
// 存儲每個節點在線段樹中的位置編號
int segmentTreePosition[100001];?

// 使用 vector 存儲圖的鄰接表
vector<int> graph[100001];?

// 第一次深度優先搜索,用于計算節點的深度、重兒子、子樹節點數量等信息
void firstDFS(int currentNode, int parentNode, int currentDepth) {
? ? parentOfNode[currentNode] = parentNode;
? ? depthOfNode[currentNode] = currentDepth;
? ? subtreeNodeCount[currentNode] = 1;
? ? int maxSubtreeSize = 0;

? ? for (int i = 0; i < graph[currentNode].size(); i++) {
? ? ? ? int adjacentNode = graph[currentNode][i];
? ? ? ? if (adjacentNode!= parentNode) {
? ? ? ? ? ? firstDFS(adjacentNode, currentNode, currentDepth + 1);
? ? ? ? ? ? subtreeNodeCount[currentNode] += subtreeNodeCount[adjacentNode];
? ? ? ? ? ? if (maxSubtreeSize < subtreeNodeCount[adjacentNode]) {
? ? ? ? ? ? ? ? heavySonOfNode[currentNode] = adjacentNode;
? ? ? ? ? ? ? ? maxSubtreeSize = subtreeNodeCount[adjacentNode];
? ? ? ? ? ? }
? ? ? ? }
? ? }
}

// 第二次深度優先搜索,用于構建重鏈剖分
void secondDFS(int currentNode, int chainTopNode) {
? ? topNodeOfChain[currentNode] = chainTopNode;
? ? segmentTreePosition[currentNode] = ++segmentTreePosition[0];
? ? if (!heavySonOfNode[currentNode]) return;
? ? secondDFS(heavySonOfNode[currentNode], chainTopNode);

? ? for (int i = 0; i < graph[currentNode].size(); i++) {
? ? ? ? int adjacentNode = graph[currentNode][i];
? ? ? ? if (parentOfNode[currentNode] == adjacentNode || heavySonOfNode[currentNode] == adjacentNode) continue;
? ? ? ? secondDFS(adjacentNode, adjacentNode);
? ? }
}

// 線段樹節點結構體
struct SegmentTreeNode {
? ? int leftBound;
? ? int rightBound;
? ? int sumValue;
? ? int lazyAddValue;
};

SegmentTreeNode segmentTree[400001];

// 構建線段樹
void buildSegmentTree(int treeNodeIndex, int left, int right) {
? ? segmentTree[treeNodeIndex].leftBound = left;
? ? segmentTree[treeNodeIndex].rightBound = right;
? ? if (left == right) return;
? ? buildSegmentTree(treeNodeIndex * 2, left, (left + right) / 2);
? ? buildSegmentTree(treeNodeIndex * 2 + 1, (left + right) / 2 + 1, right);
}

// 下傳線段樹的懶標記
void pushDownLazyTag(int treeNodeIndex) {
? ? segmentTree[treeNodeIndex * 2].lazyAddValue += segmentTree[treeNodeIndex].lazyAddValue;
? ? segmentTree[treeNodeIndex * 2 + 1].lazyAddValue += segmentTree[treeNodeIndex].lazyAddValue;
? ? segmentTree[treeNodeIndex * 2].sumValue += (segmentTree[treeNodeIndex * 2].rightBound - segmentTree[treeNodeIndex * 2].leftBound + 1) * segmentTree[treeNodeIndex].lazyAddValue;
? ? segmentTree[treeNodeIndex * 2 + 1].sumValue += (segmentTree[treeNodeIndex * 2 + 1].rightBound - segmentTree[treeNodeIndex * 2 + 1].leftBound + 1) * segmentTree[treeNodeIndex].lazyAddValue;
? ? segmentTree[treeNodeIndex].lazyAddValue = 0;
}

// 在線段樹上進行區間修改操作
void updateSegmentTree(int treeNodeIndex, int left, int right) {
? ? if (segmentTree[treeNodeIndex].rightBound < left || segmentTree[treeNodeIndex].leftBound > right) return;
? ? if (segmentTree[treeNodeIndex].leftBound >= left && segmentTree[treeNodeIndex].rightBound <= right) {
? ? ? ? segmentTree[treeNodeIndex].sumValue += segmentTree[treeNodeIndex].rightBound - segmentTree[treeNodeIndex].leftBound + 1;
? ? ? ? segmentTree[treeNodeIndex].lazyAddValue++;
? ? ? ? return;
? ? }
? ? pushDownLazyTag(treeNodeIndex);
? ? updateSegmentTree(treeNodeIndex * 2, left, right);
? ? updateSegmentTree(treeNodeIndex * 2 + 1, left, right);
? ? segmentTree[treeNodeIndex].sumValue = segmentTree[treeNodeIndex * 2].sumValue + segmentTree[treeNodeIndex * 2 + 1].sumValue;
}

// 在線段樹上查詢單點的值
int querySegmentTree(int treeNodeIndex, int targetPosition) {
? ? if (segmentTree[treeNodeIndex].rightBound < targetPosition || segmentTree[treeNodeIndex].leftBound > targetPosition) return 0;
? ? if (segmentTree[treeNodeIndex].leftBound == segmentTree[treeNodeIndex].rightBound) return segmentTree[treeNodeIndex].sumValue;
? ? pushDownLazyTag(treeNodeIndex);
? ? return querySegmentTree(treeNodeIndex * 2, targetPosition) + querySegmentTree(treeNodeIndex * 2 + 1, targetPosition);
}

int main() {
? ? int node1, node2;
? ? char operationType;
? ? cin >> nodeCount >> operationCount;
? ? for (int i = 1; i < nodeCount; i++) {
? ? ? ? cin >> node1 >> node2;
? ? ? ? graph[node1].push_back(node2);
? ? ? ? graph[node2].push_back(node1); // 存儲無向邊
? ? }

? ? firstDFS(1, 0, 1);
? ? secondDFS(1, 1);
? ? buildSegmentTree(1, 1, nodeCount);

? ? while (operationCount--) {
? ? ? ? cin >> operationType >> node1 >> node2;
? ? ? ? if (operationType == 'P') {
? ? ? ? ? ? while (topNodeOfChain[node1]!= topNodeOfChain[node2]) {
? ? ? ? ? ? ? ? if (depthOfNode[topNodeOfChain[node1]] < depthOfNode[topNodeOfChain[node2]]) swap(node1, node2);
? ? ? ? ? ? ? ? updateSegmentTree(1, segmentTreePosition[topNodeOfChain[node1]], segmentTreePosition[node1]);
? ? ? ? ? ? ? ? node1 = parentOfNode[topNodeOfChain[node1]];
? ? ? ? ? ? }
? ? ? ? ? ? if (depthOfNode[node1] > depthOfNode[node2]) swap(node1, node2);
? ? ? ? ? ? updateSegmentTree(1, segmentTreePosition[node1] + 1, segmentTreePosition[node2]); // 避開最近公共祖先
? ? ? ? } else {
? ? ? ? ? ? if (parentOfNode[node1] == node2) cout << querySegmentTree(1, segmentTreePosition[node1]) << endl;
? ? ? ? ? ? else cout << querySegmentTree(1, segmentTreePosition[node2]) << endl; // 判斷該邊的邊權是哪個點的點權
? ? ? ? }
? ? }
? ? return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88604.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88604.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88604.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

NestJS

文章的地址 NestJShttps://equinox-primrose-ceb.notion.site/NestJS-22d4b8031e0f80b39fc7fe1ff111f802 不產生測試的.spec.ts文件的配置 "generateOptions": {"spec": false }創建模型 nest g m xx 創建服務 nest g s xx 創建處理 nest g c xx CRU…

vue入門學習教程

一、介紹 vue是一款用于構建用戶界面的 JavaScript 框架。基于標準 HTML、CSS 和 JavaScript 構建&#xff0c;并提供了一套聲明式的、組件化的編程模型&#xff0c;幫助你高效地開發用戶界面。 二、使用和安裝 方法1&#xff1a;在html代碼中直接使用<script>導入&…

C++類對象多態基礎語法【超詳細】

文章目錄前言1. 虛函數1.1 現象1.2 多態1.3 析構函數1.4 override和final1.5 重載、隱藏、重寫對比2. 抽象類2.1 抽象類特性2.2 抽象類的應用場景3. 多態實現的底層原理4. 靜態綁定和動態綁定5. 總結前言 多態是面向對象三大特性之一&#xff0c;也是細節最多的語法之一。學習…

Flask 入門到實戰(3):用 SQLAlchemy 優雅操作數據庫

深入理解 Flask ORM&#xff1a;用 SQLAlchemy 優雅操作數據庫一、前言&#xff1a;什么是 ORM&#xff1f;為什么要用它&#xff1f; 傳統數據庫操作要寫 SQL&#xff0c;比如&#xff1a; SELECT * FROM users WHERE id 1;而使用 ORM 后&#xff0c;你可以這樣寫&#xff1a…

源表=電源+數字表?一文看懂SMU源表 2025-04-14

源表(Source Meter Unit, SMU)廣泛用于半導體器件、材料、醫療、發光器件與光通信等行業,測量器件的伏安(I-V)特性曲線、絕緣材料的電阻值(電阻率)、電容的絕緣電阻(漏電流)、光電器件的暗電流或者L-I-V等。 源表的名稱已經清晰的告訴我們,它包含了高精度電源輸出和…

單片機STM32F103:DMA的原理以及應用

STM32F103系列微控制器&#xff08;基于ARM Cortex-M3內核&#xff09;集成了**DMA&#xff08;Direct Memory Access&#xff0c;直接內存訪問&#xff09;**控制器&#xff0c;用于在存儲器與外設、存儲器與存儲器之間高效傳輸數據&#xff0c;減少CPU的干預&#xff0c;從而…

Webview 中可用的 VS Code 方法

在 VS Code Webview 的 HTML 中&#xff0c;不能直接調用 VS Code 的 API&#xff08;如 vscode.window.showInformationMessage&#xff09;&#xff0c;但可以通過 acquireVsCodeApi() 獲取一個受限的 vscode 對象&#xff0c;用于與插件主程序通信。以下是詳細說明和示例&am…

Qt:布局管理器Layout

目錄 布局管理器 QVBoxLayout QHBoxLayout QGirdLayout QFormLayout Spacer 布局管理器 在以往的界面操作上&#xff0c;都是程序員手動拖動控件來布局&#xff0c;這種方式有一些不足之處&#xff0c;比如不能很好的把握控件之間的距離&#xff0c;以及控件的大小&…

【Java編程動手學】深入剖析Java網絡編程:原理、協議與應用

文章目錄一、引言二、計算機網絡基礎1、計算機網絡的概念2、網絡地址的重要性三、套接字編程&#xff1a;網絡通信的基石1、套接字的概念2、TCP通信編程示例四、TCP通信編程&#xff1a;可靠的數據傳輸1、TCP協議的特點2、實際應用中的TCP通信五、UDP通信編程&#xff1a;高效的…

vue3.2 前端動態分頁算法

文章目錄背景思路頁面情況核心代碼小結效果背景 1. 后臺接口只是動態返回一個數組的數據&#xff0c;前端需要根據數據量的大小判斷是否需要分頁&#xff0c;頁面高度固定2. 頁面根據頁數大小有不同的展示a. 只有一頁 頭部 內容 統計 尾部b. 多頁i. 第一頁 頭部 內容 尾…

UC瀏覽器PC版自2016年后未再更新不支持vue3

win uc瀏覽器&#xff0c;點擊頁面觸發異常。UC瀏覽器PC版自2016年后未再更新&#xff08;最新版本停留在Chromium 50內核&#xff09;。其內置內核版本較低&#xff08;如Trident/Blink舊版&#xff09;&#xff0c;無法支持Vue 3等現代前端框架的語法特性&#xff08;如ES6、…

亞古數據:澳大利亞公司的ABN和ACN號碼是什么?

在跨國商業的迷宮中&#xff0c;了解目標市場的公司注冊細節是一項不可或缺的技能。對于與中國企業有業務往來的朋友們來說&#xff0c;澳大利亞這片充滿機遇的土地上&#xff0c;兩個縮寫——ABN與ACN&#xff0c;如同解鎖合作之門的密鑰&#xff0c;顯得尤為重要。今天&#…

LangChain框架 Prompts、Agents 應用

目錄 (Prompts)提示作用 Prompts 常見操作 基礎 PromptTemplate 使用 Few-shot 提示模板 ChatPromptTemplate (對話提示模板) (Agents)代理作用 Agents 常見操作 基礎 Agent 使用 自定義工具 Agent 高級應用示例 帶記憶的對話代理 使用本地模型的代理 結構化輸出代…

模擬實現unordered_map

1.定義unordered_map 是 C 標準庫中的哈希表容器&#xff0c;特點是無序存儲、平均 O (1) 時間復雜度的插入 / 查找 / 刪除操作。其核心原理是通過哈希函數將關鍵字映射到哈希桶&#xff08;bucket&#xff09;&#xff0c;再通過鏈表或紅黑樹處理哈希沖突。2.實現原理1. 哈希表…

史上最詳細Java并發多線程(面試必備,一篇足矣)

第一章&#xff1a;線程基礎 1.1 線程與進程 進程&#xff1a;系統資源分配的基本單位&#xff0c;擁有獨立的內存空間 線程&#xff1a;CPU調度的基本單位&#xff0c;共享進程內存空間 關系&#xff1a;一個進程可包含多個線程&#xff0c;線程切換成本遠低于進程 1.2 線程的…

【DataFlow】數據合成流水線工具

1.整體解讀 核心思想&#xff1a;以數據為中心的AI&#xff08;Data-Centric AI&#xff09; DataFlow 的核心目標是通過一系列自動化“流水線”&#xff08;Pipelines&#xff09;來處理和生成高質量的數據&#xff0c;從而提升大語言模型&#xff08;LLM&#xff09;在特定領…

Hangfire 調用報錯解決方案總結

System.ArgumentNullException: 值不能為 null 錯誤在使用 Hangfire 時確實是一個常見問題&#xff0c;特別是在配置 Hangfire 服務器時。問題分析這個錯誤通常發生在以下情況&#xff1a;沒有正確配置 Hangfire 服務器隊列配置缺失或不正確連接字符串配置問題解決方案要點正確…

MySQL的使用

MySQL的使用一、mysql中的周邊命令1. 檢查版本2. 查看字符集3. 查看客戶端連接4. 查看最后一條警告消息二、數據庫、數據表的管理1. 語法規則2. 數據庫2.1 查看數據庫2.2 創建數據庫2.3 選擇數據庫2.4 查看創建數據庫命令2.5 創建庫時添加字符集2.6 修改數據庫字符集2.7 刪除數…

2025Nginx最新版講解/面試

維護系統多服務器部署&#xff0c;將我們請求代理到各個服務器。代理正向代理&#xff0c;代理對象是我們的客戶端&#xff0c;目標對象不知道我們用戶。VPN就是典型的正向代理。反向代理&#xff0c;代理對象是服務端&#xff0c;用戶不知道服務端具體信息。而這正是Nginx所做…

JAVASCRIPT 前端數據庫-V8--仙盟數據庫架構-—-—仙盟創夢IDE

老版本 在v1 版本中我們講述了 基礎版的應用 JAVASCRIPT 前端數據庫-V1--仙盟數據庫架構-—-—仙盟創夢IDE-CSDN博客 接下載我們做一個更復雜的的其他場景 由于&#xff0c;V1查詢字段必須 id 接下來我們修改了了代碼 JAVASCRIPT 前端數據庫-V2--仙盟數據庫架構-—-—仙盟創…