主席树+线段树合并。

首先我们想一想如果只有一个结点的话,我们弄一个权值线段树就可以随便维护了。

那么我们可以运用差分的思想,把一个询问拆成四个操作,对于一个询问$(x, y, v)$,我们在$x$的$k$处$ + 1$,在$y$的$k$处$ + 1$,在$lca(x, y)$处$ - 1$,在$fa(lca(x, y))$处$ - 1$,那么每一个点最后的权值线段树的样子就相当于把它和它的子树中的权值线段树全部合并之后得到的线段树。

动态开点就可以了。

前置技能:线段树合并。     戳这里

这样子我们往下搜一遍把每一个点和它的儿子合并,然后记录一下答案就可以了。

不会算时间复杂度QωQ。

另外,这题数据很卡,我写了内存回收 + $queue$开了$O2$才卡过。

Code:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std; const int N = 1e5 + ;
const int Lg = ; int n, m, maxn = , tot = , head[N], ans[N];
int fa[N][Lg], dep[N], inx[N], iny[N], inv[N], val[N]; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} struct Innum {
int val, id;
} in[N]; bool cmp(const Innum &x, const Innum &y) {
if(x.val != y.val) return x.val < y.val;
else return x.id < y.id;
} inline void swap(int &x, int &y) {
int t = x; x = y; y = t;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} inline int min(int x, int y) {
return x > y ? y : x;
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void discrete() {
sort(in + , in + + m, cmp);
for(int cnt = , i = ; i <= m; i++) {
if(in[i].val != in[i - ].val) ++cnt;
chkMax(maxn, cnt);
inv[in[i].id] = cnt;
val[cnt] = in[i].val;
}
} void dfs(int x, int fat, int depth) {
dep[x] = depth, fa[x][] = fat;
for(int i = ; i <= ; i++)
fa[x][i] = fa[fa[x][i - ]][i - ];
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs(y, x, depth + );
}
} inline int getLca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = ; i >= ; i--)
if(dep[fa[x][i]] >= dep[y])
x = fa[x][i];
if(x == y) return x;
for(int i = ; i >= ; i--)
if(fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][];
} namespace PSegT {
struct Node {
int lc, rc, sum, col;
} s[N * ]; int root[N], nodeCnt = ; queue <int> Q; inline void push(int x) {
Q.push(x);
} inline int newNode() {
if(Q.empty()) return ++nodeCnt;
else {
int res = Q.front();
Q.pop();
return res;
}
} #define lc(p) s[p].lc
#define rc(p) s[p].rc
#define sum(p) s[p].sum
#define col(p) s[p].col
#define mid ((l + r) >> 1) inline void up(int p) {
if(!p) return;
if(sum(lc(p)) < sum(rc(p))) col(p) = col(rc(p)), sum(p) = sum(rc(p));
else col(p) = col(lc(p)), sum(p) = sum(lc(p));
} void modify(int &p, int l, int r, int x, int v) {
if(!p) p = newNode();
if(l == r) {
sum(p) += v;
if(sum(p) > ) col(p) = l;
else col(p) = ;
return;
} if(x <= mid) modify(lc(p), l, mid, x, v);
else modify(rc(p), mid + , r, x, v);
up(p);
} int merge(int u, int v, int l, int r) {
if(!u || !v) return u + v;
int p = newNode();
if(l == r) {
sum(p) = sum(u) + sum(v);
if(sum(p) > ) col(p) = l;
else col(p) = ;
} else {
lc(p) = merge(lc(u), lc(v), l, mid);
rc(p) = merge(rc(u), rc(v), mid + , r);
up(p);
}
push(u), push(v);
return p;
} } using namespace PSegT; void solve(int x) {
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x][]) continue;
solve(y);
root[x] = merge(root[x], root[y], , maxn);
} /* printf("%d: ", x);
for(int i = 1; i <= maxn; i++)
printf("%d ", query(root[id[x] - 1], root[id[x]], 1, maxn, i));
printf("\n"); */ ans[x] = val[s[root[x]].col];
} int main() {
read(n), read(m);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
}
dfs(, , ); // maxn = 1e5; for(int i = ; i <= m; i++) {
read(inx[i]), read(iny[i]), read(inv[i]);
in[i].id = i, in[i].val = inv[i];
}
discrete(); for(int x, y, v, z, w, i = ; i <= m; i++) {
x = inx[i], y = iny[i], v = inv[i];
z = getLca(x, y), w = fa[z][]; /* vec[x].push_back(pin(v, 1));
vec[y].push_back(pin(v, 1));
vec[z].push_back(pin(v, -1));
if(w) vec[w].push_back(pin(v, -1)); */ modify(root[x], , maxn, v, );
modify(root[y], , maxn, v, );
modify(root[z], , maxn, v, -);
if(w) modify(root[w], , maxn, v, -);
} /* printf("\n");
for(int i = 1; i <= n; i++) {
printf("%d: ", i);
for(int j = 1; j <= maxn; j++)
printf("%d ", query(root[id[i] - 1], root[id[i] + siz[i] - 1], 1, maxn, j));
printf("\n");
}
printf("\n"); */ solve(); for(int i = ; i <= n; i++)
printf("%d\n", ans[i]); return ;
}

最新文章

  1. Lambert(朗伯)光照模型 和Half Lambert的区别
  2. [Effective Sublime Text] (01) Sublime Text 3 开发环境初始化
  3. GJM : Unity3D - NetWork - Hight Level API ( HLAPI) [转载]
  4. BZOJ4605 : 崂山白花蛇草水
  5. jsp学习---css基础知识学习,float,position,padding,div,margin
  6. 比较好的文件复制工具fastcopy和校验工具
  7. 获取手机IMEI 号和 IP
  8. c#中委托和事件(续)(转)
  9. JAXB - Annotations, Annotation for Classes: XmlType
  10. dom操作之开关灯
  11. Java中加载配置文件的集中方式,以及利用ClassLoader加载文件 .
  12. (原) Jquery 判断移动设备是IOS / Android系统
  13. iOS开发——打开手机相册,获取图片
  14. 201521123080《Java程序设计》第6周学习总结
  15. Spring_Spring与AOP_AspectJ基于注解的AOP实现
  16. asp.net core中写入自定义中间件
  17. 偶发异常BUG,如何高效精准分析排查定位?
  18. MSF banner
  19. day65 request对象,以及方法,response对象,render,redirect
  20. Dell灵越 5559笔记本安装固态硬盘 BIOS设置

热门文章

  1. OpenStack Neutron 之 Load Balance
  2. POJ2253 frogger 最短路 floyd
  3. Linux开发引导
  4. BZOJ 3357 [Usaco2004]等差数列:map优化dp
  5. Atom插件及使用
  6. 使用命令行生成 APNG 图片
  7. 关于MFC视图文档框架的理解-1
  8. list dict set comprehension 列表推导式 (字典推导式,集合推导式)
  9. 【leetcode刷题笔记】Valid Palindrome
  10. uimsbf和 bslbf的含义