题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5029

Problem Description
The soil is cracking up because of the drought and the rabbit kingdom is facing a serious famine. The RRC(Rabbit Red Cross) organizes the distribution of relief grain in the disaster area.

We can regard the kingdom as a tree with n nodes and each node stands for a village. The distribution of the relief grain is divided into m phases. For each phases, the RRC will choose a path of the tree and distribute some relief grain of a certain type for every village located in the path.

There are many types of grains. The RRC wants to figure out which type of grain is distributed the most times in every village.

 
Input
The input consists of at most 25 test cases.

For each test case, the first line contains two integer n and m indicating the number of villages and the number of phases.

The following n-1 lines describe the tree. Each of the lines contains two integer x and y indicating that there is an edge between the x-th village and the y-th village.
  
The following m lines describe the phases. Each line contains three integer x, y and z indicating that there is a distribution in the path from x-th village to y-th village with grain of type z. (1 <= n <= 100000, 0 <= m <= 100000, 1 <= x <= n, 1 <= y <= n, 1 <= z <= 100000)

The input ends by n = 0 and m = 0.

 
Output
For each test case, output n integers. The i-th integer denotes the type that is distributed the most times in the i-th village. If there are multiple types which have the same times of distribution, output the minimal one. If there is no relief grain in a village, just output 0.
 
题目大意:有一棵n个点的数,有m个操作,每次给路径path(x, y)分配一个值z。最后问每个点被分配次数最多的值,如有多个输出最小的一个。
思路:首先我们可以注意到,要输出结果只有最后一个,所有操作的顺序都是无关紧要的,我们可以按自己喜欢的顺序来做。
 
这个问题是在树上做的,我们先来简化一下问题,如果这是一维的线段,每次在一个区间上操作,怎么办。
这个问题的解法是,按值建树,对于每一个操作(x, y, z),也就是给区间[x, y + 1)分配资源,可以给 x 标记一个 +z,给 y + 1 标记一个 -z。
按坐标从左往右扫,对于每一个 x,把所有标记压入线段树,然后再求 x 的答案。总体复杂度为O(nlogn)。
 
回到本题的问题,这题是在树上做的,按上面的做法,可以想到,对于操作(x, y, z),求出其lca,把它分为两条链[x, lca],[y, lca)。
然后按dfs序做,此时对于每一个结点,我们在做完它的所有子节点后,要把子节点的所有线段树合并,再加上它自身的标记,再求出这个结点的答案。
但是随意地合并线段树,可能会使得复杂度高达O(n^2logn)。这里采取启发式合并,每次把小的线段树合并到大的线段树上。
不考虑减的标记,标记最多有3n个,那么每个标记被合并之后,它所在的线段树大小至少会增加两倍,那么最多被合并O(logn)次。
在考虑减的标记的时候,虽然上述分析不适用了,但是感觉上减少了标记只会令复杂度降低。所以总复杂度为O(n(logn)^2)。
 
代码(3046MS):
 #include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int, int> PII; const int MAXV = ;
const int MAXE = MAXV << ;
const int MAXT = MAXV << ; int head[MAXV], ecnt;
int to[MAXE], next[MAXE];
int n, m, maxz; void init() {
memset(head + , -, n * sizeof(int));
ecnt = ;
} void add_edge(int u, int v) {
to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; next[ecnt] = head[v]; head[v] = ecnt++;
} #define mid ((l + r) >> 1)
struct Node {
Node *lson, *rson;
int val, cnt, size;
Node() {
val = cnt = size = ;
}
void update() {
Node *s = lson->cnt >= rson->cnt ? lson : rson;
val = s->val;
cnt = s->cnt;
size = lson->size + rson->size;
}
} *nil;
Node statePool[MAXT * ];
Node *stk[MAXT * ];
int top, scnt; Node* new_node() {
Node *p;
if(top) p = stk[--top];
else p = &statePool[scnt++];
p->lson = p->rson = nil;
p->val = p->cnt = p->size = ;
return p;
} void del_node(Node *p) {
stk[top++] = p;
} void remove(Node *y) {
if(y->lson != nil) remove(y->lson);
if(y->rson != nil) remove(y->rson);
del_node(y);
} void modify(Node *&x, int l, int r, int pos, int val) {
if(x == nil) x = new_node();
if(l == r) {
x->val = l;
x->cnt += val;
x->size = (x->cnt > );
} else {
if(pos <= mid) modify(x->lson, l, mid, pos, val);
if(mid < pos) modify(x->rson, mid + , r, pos, val);
x->update();
}
} void merge(Node *x, Node *y, int l, int r) {
if(y->size != ) {
if(l == r) {
modify(x, , maxz, l, y->cnt);
} else {
merge(x, y->lson, l, mid);
merge(x, y->rson, mid + , r);
}
}
} Node* merge(Node *x, Node *y) {
if(x->size < y->size) swap(x, y);
merge(x, y, , maxz);
remove(y);
return x;
} vector<PII> query[MAXV];
struct Modify {
int u, v, c, lca;
void read(int i) {
scanf("%d%d%d", &u, &v, &c);
maxz = max(maxz, c);
query[u].push_back(make_pair(v, i));
query[v].push_back(make_pair(u, i));
}
} ask[MAXV];
int fa[MAXV];
bool vis[MAXV]; int find_set(int x) {
return fa[x] == x ? x : fa[x] = find_set(fa[x]);
} void lca(int u, int f) {
for(int p = head[u]; ~p; p = next[p]) {
int &v = to[p];
if(v == f || vis[v]) continue;
lca(v, u);
fa[v] = u;
}
vis[u] = true;
for(vector<PII>::iterator it = query[u].begin(); it != query[u].end(); ++it) {
if(vis[it->first]) {
ask[it->second].lca = find_set(it->first);
}
}
} vector<PII> pre[MAXV], nxt[MAXV];
int ans[MAXV]; Node* dfs(int u, int f) {
Node *x = new_node();
for(int p = head[u]; ~p; p = next[p]) {
int v = to[p];
if(v == f) continue;
x = merge(x, dfs(v, u));
}
for(vector<PII>::iterator it = pre[u].begin(); it != pre[u].end(); ++it)
modify(x, , maxz, it->first, it->second);
ans[u] = x->val;
for(vector<PII>::iterator it = nxt[u].begin(); it != nxt[u].end(); ++it)
modify(x, , maxz, it->first, it->second);
return x;
} void solve() {
for(int i = ; i <= n; ++i) {
fa[i] = i;
vis[i] = false;
pre[i].clear(); nxt[i].clear();
}
lca(, );
for(int i = ; i < m; ++i) {
const Modify &t = ask[i];
pre[t.u].push_back(make_pair(t.c, ));
pre[t.v].push_back(make_pair(t.c, ));
pre[t.lca].push_back(make_pair(t.c, -));
nxt[t.lca].push_back(make_pair(t.c, -));
}
top = scnt = ;
Node *p = dfs(, );
if(p != nil) remove(p); for(int i = ; i <= n; ++i)
printf("%d\n", ans[i]);
} int main() {
nil = new Node();
nil->lson = nil->rson = nil; while(scanf("%d%d", &n, &m) != EOF) {
if(n == && m == ) break;
init();
for(int i = , u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
add_edge(u, v);
}
for(int i = ; i <= n; ++i) query[i].clear();
maxz = ;
for(int i = ; i < m; ++i) ask[i].read(i);
solve();
}
}

最新文章

  1. PHP 生成验证码
  2. php原型模式的研究
  3. JavaScript求和
  4. sublime学习
  5. 转 git使用命令, 特别:git checkout -b a 与 git branch a区别
  6. form作为module name 悲剧了
  7. 【svn】 SVN错误:Attempted to lock an already-locked dir
  8. 在windows下添加php的Imagick扩展
  9. locate: can not stat () `/var/lib/mlocate/mlocate.db&#39;: No such file or directory
  10. 老李分享:https协议
  11. Python安装与环境变量的配置
  12. R语言-图的要素颜色
  13. 机器学习技法笔记:12 Neural Network
  14. javascript篇-typeof,instanceof,constructor,toString判断数据类型的用法和区别
  15. gitlab 部署
  16. Expo大作战(三)--针对已经开发过react native项目开发人员有针对性的介绍了expo,expo的局限性,开发时项目选型注意点等
  17. 20155234《网路对抗》Exp9 WEB安全基础
  18. linux下如何模拟按键输入和模拟鼠标【转】
  19. Android MD5校验码的生成与算法实现
  20. Java 訪问权限控制:你真的了解 protected keyword吗?

热门文章

  1. sql CRUD 增删改查复习汇总
  2. cwe
  3. Visual Studio 2010扩展让JS与CSS实现折叠
  4. sublimtext2 资源
  5. Best practice: escape, or encodeURI / encodeURIComponent
  6. mongoDB 安装配置
  7. [LeetCode]题解(python):056-Merge Intervals
  8. POI对Excel
  9. inline-block元素的空白间距
  10. RHEL6解决无法使用YUM源问题