路径(x, y) +z : u处+z, v处+z, lca(u,v)处-z, fa(lca)处-z, 然后dfs一遍, 用线段树合并. O(M log M + M log N). 复杂度看起来不高, 但是跑起来很慢.

另一种做法是先树链剖分, 转成序列上的情况, 然后依旧是差分+线段树维护, O(M log N log M). 但是实际跑起来好像更快...

------------------------------------------------------------------------------

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
const int maxn = 100009;
 
int N, M;
int Hash[maxn], Hn;
 
template<class T>
inline void Min(T &x, T t) {
if(t < x) x = t;
}
template<class T>
inline void Max(T &x, T t) {
if(t > x) x = t;
}
 
inline int getint() {
char c = getchar();
for(; !isdigit(c); c = getchar());
int ret = 0;
for(; isdigit(c); c = getchar())
ret = ret * 10 + c - '0';
return ret;
}
 

struct L {

int x;
L* n;
} Lpool[maxn * 4], *Pt = Lpool, *Head[maxn];
 
inline void AddL(int a, int b) {
Pt->x = b, Pt->n = Head[a], Head[a] = Pt++;
}
 
struct O {
int x, y, z;
} o[maxn];
 
struct edge {
int t;
edge* n;
} E[maxn << 1], *ept = E, *H[maxn];
 
inline void AddEdge(int u, int v) {
ept->t = v, ept->n = H[u], H[u] = ept++;
}
 
void Init() {
Hn = 0;
int u, v;
N = getint(), M = getint();
for(int i = 1; i < N; i++) {
u = getint() - 1, v = getint() - 1;
AddEdge(u, v);
AddEdge(v, u);
}
for(int i = 0; i < M; i++) {
o[i].x = getint() - 1;
o[i].y = getint() - 1;
Hash[Hn++] = o[i].z = getint();
}
Hash[Hn++] = 0;
sort(Hash, Hash + Hn);
Hn = unique(Hash, Hash + Hn) - Hash;
for(int i = 0; i < M; i++)
o[i].z = lower_bound(Hash, Hash + Hn, o[i].z) - Hash;
}
 
int top[maxn], sz[maxn], ch[maxn], fa[maxn], dep[maxn];
int Top;
 
void dfs(int x) {
sz[x] = 1, ch[x] = -1;
for(edge* e = H[x]; e; e = e->n) if(e->t != fa[x]) {
dep[e->t] = dep[x] + 1;
fa[e->t] = x;
dfs(e->t);
sz[x] += sz[e->t];
if(!~ch[x] || sz[ch[x]] < sz[e->t]) ch[x] = e->t;
}
}
 
void DFS(int x) {
top[x] = Top;
if(~ch[x]) DFS(ch[x]);
for(edge* e = H[x]; e; e = e->n)
if(e->t != fa[x] && e->t != ch[x]) DFS(Top = e->t);
}
 
int LCA(int x, int y) {
for(; top[x] != top[y]; x = fa[top[x]])
if(dep[top[x]] < dep[top[y]]) swap(x, y);
return dep[x] < dep[y] ? x : y;
}
 
struct Node {
Node *lc, *rc;
int mx, Id;
inline void upd() {
mx = -maxn, Id = maxn;
if(lc) Max(mx, lc->mx);
if(rc) Max(mx, rc->mx);
if(lc && lc->mx == mx) Min(Id, lc->Id);
if(rc && rc->mx == mx) Min(Id, rc->Id);
}
} pool[maxn * 70], *pt = pool, *V[maxn];
 
int Val, Pos;
 
void Modify(Node*&t, int l, int r) {
if(!t)
(t = pt++)->mx = 0;
int m = (l + r) >> 1;
if(l == r) {
t->mx += Val;
t->Id = m;
} else {
Pos <= m ? Modify(t->lc, l, m) : Modify(t->rc, m + 1, r);
t->upd();
}
if(!t->mx) t = 0;
}
 
Node* Merge(Node* a, Node* b, int l, int r) {
int m = (l + r) >> 1;
if(!a) return b;
if(!b) return a;
if(l != r) {
a->lc = Merge(a->lc, b->lc, l, m);
a->rc = Merge(a->rc, b->rc, m + 1, r);
a->upd();
} else
a->mx += b->mx;
return a;
}
 
int ans[maxn];
 
void calc(int x) {
for(L* t = Head[x]; t; t = t->n) {
if(t->x > 0)
Pos = t->x, Val = 1;
else
Pos = -t->x, Val = -1;
Modify(V[x], 1, Hn);
}
for(edge* e = H[x]; e; e = e->n) if(e->t != fa[x]) {
calc(e->t);
V[x] = Merge(V[x], V[e->t], 1, Hn);
}
ans[x] = V[x] ? V[x]->Id : 0;
}
 
void Work() {
fa[0] = -1;
dep[0] = 0;
dfs(0);
DFS(Top = 0);
for(int i = 0; i < M; i++) {
int lca = LCA(o[i].x, o[i].y);
AddL(o[i].x, o[i].z);
AddL(o[i].y, o[i].z);
AddL(lca, -o[i].z);
if(~fa[lca]) AddL(fa[lca], -o[i].z);
}
calc(0);
for(int i = 0; i < N; i++)
printf("%d\n", Hash[ans[i]]);
}
 

int main() {

Init();
Work();
return 0;
}

------------------------------------------------------------------------------

3307: 雨天的尾巴

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 267  Solved: 127
[Submit][Status][Discuss]

Description

N个点,形成一个树状结构。有M次发放,每次选择两个点x,y
对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成
所有发放后,每个点存放最多的是哪种物品。

Input

第一行数字N,M
接下来N-1行,每行两个数字a,b,表示a与b间有一条边
再接下来M行,每行三个数字x,y,z.如题

Output

输出有N行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有
多种物品的数量一样,输出编号最小的。如果某个点没有物品
则输出0

Sample Input

20 50
8 6
10 6
18 6
20 10
7 20
2 18
19 8
1 6
14 20
16 10
13 19
3 14
17 18
11 19
4 11
15 14
5 18
9 10
12 15
11 14 87
12 1 87
14 3 84
17 2 36
6 5 93
17 6 87
10 14 93
5 16 78
6 15 93
15 5 16
11 8 50
17 19 50
5 4 87
15 20 78
1 17 50
20 13 87
7 15 22
16 11 94
19 8 87
18 3 93
13 13 87
2 1 87
2 6 22
5 20 84
10 12 93
18 12 87
16 10 93
8 17 93
14 7 36
7 4 22
5 9 87
13 10 16
20 11 50
9 16 84
10 17 16
19 6 87
12 2 36
20 9 94
9 2 84
14 1 94
5 5 94
8 17 16
12 8 36
20 17 78
12 18 50
16 8 94
2 19 36
10 18 36
14 19 50
4 12 50

Sample Output

87
36
84
22
87
87
22
50
84
87
50
36
87
93
36
94
16
87
50
50

1<=N,M<=100000
1<=a,b,x,y<=N
1<=z<=10^9

HINT

Source

BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )的更多相关文章

  1. Bzoj 3307 雨天的尾巴(线段树合并+树上差分)

    C. 雨天的尾巴 题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入格式 第 ...

  2. BZOJ_3307_雨天的尾巴_线段树合并+树上差分

    BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...

  3. 【BZOJ 3307】 3307: 雨天的尾巴 (线段树+树链剖分)

    3307: 雨天的尾巴 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 458  Solved: 210 Description N个点,形成一个树状结 ...

  4. P4556 [Vani有约会]雨天的尾巴(线段树合并+lca)

    P4556 [Vani有约会]雨天的尾巴 每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作. 离线处理完向上合并就好了 luogu倍增lca被卡了5分.....于是用rmq维护.... 常 ...

  5. P4556 [Vani有约会]雨天的尾巴 (线段树合并)

    P4556 [Vani有约会]雨天的尾巴 题意: 首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋 ...

  6. P4556 [Vani有约会]雨天的尾巴(线段树合并)

    传送门 一道线段树合并 首先不难看出树上差分 我们把每一次修改拆成四个,在\(u,v\)分别放上一个,在\(lca\)和\(fa[lca]\)各减去一个,那么只要统计一下子树里的总数即可 然而问题就在 ...

  7. 雨天的尾巴(bzoj3307)(线段树合并+树上差分)

    \(N\)个点,形成一个树状结构.有\(M\)次发放,每次选择两个点\(x,y\) 对于\(x\)到\(y\)的路径上(含\(x,y\))每个点发一袋\(Z\)类型的物品.完成 所有发放后,每个点存放 ...

  8. 洛谷P4556 雨天的尾巴(线段树合并)

    洛谷P4556 雨天的尾巴 题目链接 题解: 因为一个点可能存放多种物品,直接开二维数组进行统计时间.空间复杂度都不能承受.因为每一个点所拥有的物品只与其子树中的点有关,所以可以考虑对每一个点来建立一 ...

  9. [bzoj3307]雨天的尾巴_线段树合并

    雨天的尾巴 bzoj-3307 题目大意:N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. ...

随机推荐

  1. css系列教程--简介及基础语法和注意事项

    css简介:css指的是层叠样式表,cascading style sheets.用来定义html中的dom节点如何展示在页面中的问题.解决了内容与表现形式的分离问题.常见的样式表有外部链接样式表和内 ...

  2. checkbox,radio,selected相关操作

    1.radio:单选框 HTML代码: <input type="radio" name="radio" id="radio1" va ...

  3. oracle函数trunc的使用

    1.日期比较时精确到日,可以使用 TRUNC(sysdate,'dd')函数.函数支持格式有:yyyy MM  dd  hh Mi可以用   select TRUNC(sysdate,'yyyy') ...

  4. Android布局控件

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout ...

  5. GPS数据处理 - 字符串函数的灵活应用

    题目内容: NMEA- 0183协议是为了在不同的GPS(全球定位系统)导航设备中建立统一的BTCM(海事无线电技术委员会)标准,由美国国家海洋电子协会(NMEA- The National Mari ...

  6. HttpClient 请求WebApi

    HttpClient client = new HttpClient(); client.BaseAddress = new Uri(ConfigurationManager.AppSettings[ ...

  7. 不同分辨率下获取不同js文件

    获取当前网站的目录  //js获取网站根路径(站点及虚拟目录),获得网站的根目录或虚拟目录的根地址 function getRootPath(){ //整个域名(如:http://vc3.cn/ind ...

  8. python之列表、字典的使用

    一.概述:以后你在Linux里面写Python脚本的时候会经常用到Python列表.字典,因为你在以后写脚本的时候,大多数情况下都是对文件进行操作处理,使用字典和列表可以很好的操作文件,得出你想要的结 ...

  9. 镍钯金工艺(ENEPIG)详解

    一.镍钯金工艺(ENEPIG)与其他工艺如防氧化(OSP),镍金(ENIG)等相比有如下优点: 1.防止“黑镍问题”的发生–没有置换金攻击镍的表面做成晶粒边界腐蚀现象. 2.化学镀钯会作为阻挡层,不会 ...

  10. 为什么不能在scrollview中直接添加一个image,然后使animation.begin()??

    http://stackoverflow.com/questions/17267451/animation-cant-begin-in-scrollview-in-windows-phone 以上是我 ...