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

《P3313 [SDOI2014] 旅行》

目描述

S 国有 N 个城市,编号从 1 到 N。城市间用 N−1 条双向道路连接,满足从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。

为了方便,我们用不同的正整数代表各种宗教,S 国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S 国为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。

在 S 国的历史上常会发生以下几种事件:

  • CC x c:城市 x 的居民全体改信了 c 教;
  • CW x w:城市 x 的评级调整为 w;
  • QS x y:一位旅行者从城市 x 出发,到城市 y,并记下了途中留宿过的城市的评级总和;
  • QM x y:一位旅行者从城市 x 出发,到城市 y,并记下了途中留宿过的城市的评级最大值。

由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。

输入格式

输入的第一行包含整数 N,Q 依次表示城市数和事件数。

接下来 N 行,第 i+1 行两个整数 Wi​,Ci​ 依次表示记录开始之前,城市 i 的评级和信仰。

接下来 N−1 行每行两个整数 x,y 表示一条双向道路。

接下来 Q 行,每行一个操作,格式如上所述。

输出格式

对每个 QS 和 QM 事件,输出一行,表示旅行者记下的数字。

输入输出样例

输入 #1复制

5 6
3 1
2 3
1 2
3 3
5 1
1 2
1 3
3 4
3 5
QS 1 5
CC 3 1
QS 1 5
CW 3 3
QS 1 5
QM 2 4

输出 #1复制

8
9
11
3

说明/提示

对于 100% 的数据,N,Q≤105,C≤105

数据保证对所有 QS 和 QM 事件,起点和终点城市的信仰相同;在任意时刻,城市的评级总是不大于 104 的正整数,且宗教值不大于 C。

代码实现:

#include <bits/stdc++.h>
using namespace std;
#define mid ((left+right)>>1)

const int MAXN = 110000;
char operation[3];

int cityCount, queryCount;
int cityRating[MAXN], cityReligion[MAXN];
int adjacencyHead[MAXN], edgeCount, nodeCount;
int heavySon[MAXN], subtreeSize[MAXN], parent[MAXN], depth[MAXN];
int nodeID[MAXN], currentID, ratingValue[MAXN], chainTop[MAXN], segmentRoot[MAXN];

struct Edge {
int next, to;
} edges[MAXN << 1];

struct SegmentTreeNode {
int leftChild, rightChild;
int sum, maxValue;
bool flag;
} treeNodes[MAXN << 4];

inline void addEdge(int from, int to) {
edges[++edgeCount].next = adjacencyHead[from];
adjacencyHead[from] = edgeCount;
edges[edgeCount].to = to;
}

void dfsForHeavyLightDecomposition1(int currentNode, int parentNode) {
depth[currentNode] = depth[parentNode] + 1;
parent[currentNode] = parentNode;
subtreeSize[currentNode] = 1;

for (int i = adjacencyHead[currentNode]; i; i = edges[i].next) {
int neighbor = edges[i].to;
if (neighbor == parentNode) continue;

dfsForHeavyLightDecomposition1(neighbor, currentNode);
subtreeSize[currentNode] += subtreeSize[neighbor];

if (subtreeSize[neighbor] > subtreeSize[heavySon[currentNode]])
heavySon[currentNode] = neighbor;
}
}

void dfsForHeavyLightDecomposition2(int currentNode, int topNode) {
nodeID[currentNode] = ++currentID;
ratingValue[currentID] = cityRating[currentNode];
chainTop[currentNode] = topNode;

if (!heavySon[currentNode]) return;
dfsForHeavyLightDecomposition2(heavySon[currentNode], topNode);

for (int i = adjacencyHead[currentNode]; i; i = edges[i].next) {
int neighbor = edges[i].to;
if (neighbor != heavySon[currentNode] && neighbor != parent[currentNode])
dfsForHeavyLightDecomposition2(neighbor, neighbor);
}
}

inline void updateParentNode(int nodeIndex) {
treeNodes[nodeIndex].sum = treeNodes[treeNodes[nodeIndex].leftChild].sum + 
treeNodes[treeNodes[nodeIndex].rightChild].sum;
treeNodes[nodeIndex].maxValue = max(treeNodes[treeNodes[nodeIndex].leftChild].maxValue,
treeNodes[treeNodes[nodeIndex].rightChild].maxValue);
}

void insertNode(int position, int left, int right, int &currentNode, int value) {
if (!currentNode) currentNode = ++nodeCount;

treeNodes[currentNode].maxValue = max(treeNodes[currentNode].maxValue, value);
treeNodes[currentNode].sum += value;

if (left == right) return;

if (position <= mid) 
insertNode(position, left, mid, treeNodes[currentNode].leftChild, value);
else 
insertNode(position, mid + 1, right, treeNodes[currentNode].rightChild, value);
}

void removeNode(int position, int left, int right, int &currentNode) {
if (left == right) {
treeNodes[currentNode].sum = treeNodes[currentNode].maxValue = 0;
return;
}

if (position <= mid) 
removeNode(position, left, mid, treeNodes[currentNode].leftChild);
else 
removeNode(position, mid + 1, right, treeNodes[currentNode].rightChild);

updateParentNode(currentNode);
}

int querySum(int queryLeft, int queryRight, int left, int right, int currentNode) {
if (left >= queryLeft && right <= queryRight) 
return treeNodes[currentNode].sum;

int result = 0;
if (queryLeft <= mid) 
result += querySum(queryLeft, queryRight, left, mid, treeNodes[currentNode].leftChild);
if (queryRight > mid) 
result += querySum(queryLeft, queryRight, mid + 1, right, treeNodes[currentNode].rightChild);

return result;
}

int queryPathSum(int startNode, int endNode, int religion) {
int result = 0;

while (chainTop[startNode] != chainTop[endNode]) {
if (depth[chainTop[startNode]] < depth[chainTop[endNode]])
swap(startNode, endNode);

result += querySum(nodeID[chainTop[startNode]], nodeID[startNode], 1, cityCount, segmentRoot[religion]);
startNode = parent[chainTop[startNode]];
}

if (depth[startNode] > depth[endNode])
swap(startNode, endNode);

result += querySum(nodeID[startNode], nodeID[endNode], 1, cityCount, segmentRoot[religion]);
return result;
}

int queryMax(int queryLeft, int queryRight, int left, int right, int currentNode) {
if (left >= queryLeft && right <= queryRight) 
return treeNodes[currentNode].maxValue;

int result = 0;
if (queryLeft <= mid) 
result = max(result, queryMax(queryLeft, queryRight, left, mid, treeNodes[currentNode].leftChild));
if (queryRight > mid) 
result = max(result, queryMax(queryLeft, queryRight, mid + 1, right, treeNodes[currentNode].rightChild));

return result;
}

int queryPathMax(int startNode, int endNode, int religion) {
int result = 0;

while (chainTop[startNode] != chainTop[endNode]) {
if (depth[chainTop[startNode]] < depth[chainTop[endNode]])
swap(startNode, endNode);

result = max(result, queryMax(nodeID[chainTop[startNode]], nodeID[startNode], 1, cityCount, segmentRoot[religion]));
startNode = parent[chainTop[startNode]];
}

if (depth[startNode] > depth[endNode])
swap(startNode, endNode);

result = max(result, queryMax(nodeID[startNode], nodeID[endNode], 1, cityCount, segmentRoot[religion]));
return result;
}

int main() {
ios::sync_with_stdio(false);
cin >> cityCount >> queryCount;

for (int i = 1; i <= cityCount; i++)
cin >> cityRating[i] >> cityReligion[i];

for (int i = 1, u, v; i < cityCount; i++) {
cin >> u >> v;
addEdge(u, v);
addEdge(v, u);
}

dfsForHeavyLightDecomposition1(1, 0);
dfsForHeavyLightDecomposition2(1, 1);

for (int i = 1; i <= cityCount; i++)
insertNode(nodeID[i], 1, cityCount, segmentRoot[cityReligion[i]], cityRating[i]);

for (int i = 1, x, y; i <= queryCount; i++) {
cin >> operation >> x >> y;

if (operation[1] == 'C') {
removeNode(nodeID[x], 1, cityCount, segmentRoot[cityReligion[x]]);
insertNode(nodeID[x], 1, cityCount, segmentRoot[y], cityRating[x]);
cityReligion[x] = y;

else if (operation[1] == 'W') {
removeNode(nodeID[x], 1, cityCount, segmentRoot[cityReligion[x]]);
insertNode(nodeID[x], 1, cityCount, segmentRoot[cityReligion[x]], y);
cityRating[x] = y;

else if (operation[1] == 'S') {
printf("%d\n", queryPathSum(x, y, cityReligion[x]));

else if (operation[1] == 'M') {
printf("%d\n", queryPathMax(x, y, cityReligion[x]));
}
}

return 0;
}

http://www.dtcms.com/a/298869.html

相关文章:

  • 关于我司即将对商业间谍行为进行法律诉讼的通知
  • C++学习笔记(十:类与对象基础)
  • 洛谷刷题7.25
  • TwinCAT3编程入门1
  • 【Mybatis】分页插件及其原理
  • 蓝桥杯java算法例题
  • powershell 实现批量把文件夹下的bmp文件转换为jpg
  • 操作系统:设计与实现(Operating System Design Implementation)
  • deepseek本地部署,轻松实现编程自由
  • 小架构step系列25:错误码
  • 储粮温度预测新方案!FEBL模型用代码实现:LSTM+注意力+岭回归的完整流程
  • 【map计算】自定义map计算
  • KNN 算法进阶:从基础到优化的深度解析
  • GaussDB 数据库架构师修炼(九) 逻辑备份实操
  • 动态规划Day1学习心得
  • JavaWeb项目(纯Servlet+JSP+前端三大件)入门(从0开始)
  • JavaSE-图书信息管理系统
  • jwt 在net9.0中做身份认证
  • 2507C++,窗口勾挂事件
  • IPv6,你开始使用了吗?
  • MATLAB 设置默认启动路径为上次关闭路径的方法
  • Linux C : 指针
  • ZYNQ芯片,SPI驱动开发自学全解析个人笔记【FPGA】【赛灵思】
  • 您的需求已被采纳
  • 【51单片机简易红绿灯计数延时】2022-9-23
  • AIStarter平台亮点解析:从ComfyUI项目上架到一键运行的完整指南
  • I/O多路复用机制中触发机制详细解析
  • 数字化转型-AI落地金字塔法则
  • 【补题】Codeforces Round 735 (Div. 2) B. Cobb
  • 卡尔曼滤波器噪声方差设置对性能影响的仿真研究