P4556 [Vani有约会]雨天的尾巴 (线段树合并)
P4556 [Vani有约会]雨天的尾巴
题意:
首先村落里的一共有n座房屋,并形成一个树状结构。然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。
题解:
树链剖分的写法很明显了,维护一个max即可
讲一下线段树合并的写法
区间更新用单点更新和差分来代替,求一个LCA,x->y的更新即可用在点x+1,点y+1,点lca(x,y)-1,点fa(lca(x,y))-1 后,线段树合并来取代, 线段树维护最多的救济粮编号val,最多救济粮的数量sum,然后在合并的时候就可以统计出u节点的答案了
代码
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
// warm heart, wagging tail,and a smile just for you!
//
// _ooOoo_
// o8888888o
// 88" . "88
// (| -_- |)
// O\ = /O
// ____/`---'\____
// .' \| |// `.
// / \||| : |||// \
// / _||||| -:- |||||- \
// | | \ - /// | |
// | \_| ''\---/'' | |
// \ .-\__ `-` ___/-. /
// ___`. .' /--.--\ `. . __
// ."" '< `.___\_<|>_/___.' >'"".
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
// \ \ `-. \_ __\ /__ _/ .-` / /
// ======`-.____`-.___\_____/___.-`____.-'======
// `=---='
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// 佛祖保佑 永无BUG
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <bitset>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
return a / gcd(a, b) * b;
}
double dpow(double a, LL b) {
double ans = 1.0;
while(b) {
if(b % 2)ans = ans * a;
a = a * a;
b /= 2;
} return ans;
}
LL quick_pow(LL x, LL y) {
LL ans = 1;
while(y) {
if(y & 1) {
ans = ans * x % mod;
} x = x * x % mod;
y >>= 1;
} return ans;
}
struct EDGE {
int v, nxt;
} edge[maxn << 1];
int head[maxn], tot;
void add_edge(int u, int v) {
edge[tot].v = v;
edge[tot].nxt = head[u];
head[u] = tot++;
}
struct node {
int l, r, sum, val;
} tree[maxn * 40];
int root[maxn];
int tree_cnt;
int sz[maxn], dep[maxn], fa[maxn], top[maxn], w[maxn], son[maxn], W[maxn], cnt;
void init() {
dep[1] = 1; fa[1] = 0;
memset(head, -1, sizeof(head));
tree_cnt = 0;
tot = 0;
cnt = 0;
}
#define ls tree[rt].l
#define rs tree[rt].r
void push_up(int rt) {
if(tree[ls].sum > tree[rs].sum) {
tree[rt].sum = tree[ls].sum;
tree[rt].val = tree[ls].val;
} else if(tree[ls].sum == tree[rs].sum) {
tree[rt].sum = tree[ls].sum;
tree[rt].val = min(tree[ls].val, tree[rs].val);
} else {
tree[rt].sum = tree[rs].sum;
tree[rt].val = tree[rs].val;
}
}
void update(int &x, int l, int r, int pos, int val) {
if(!x) x = ++tree_cnt;
if(l == r) {
tree[x].sum += val;
if(tree[x].sum) {
tree[x].val = l;
} else {
tree[x].val = 0;
}
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(tree[x].l, l, mid, pos, val);
else update(tree[x].r, mid + 1, r, pos, val);
push_up(x);
}
void merge(int &x, int y, int l, int r) {
if(!x || !y) {
x = x + y;
return;
}
if(l == r) {
tree[x].sum += tree[y].sum;
if(tree[x].sum) {
tree[x].val = l;
} else {
tree[x].val = 0;
}
return;
}
int mid = (l + r) >> 1;
merge(tree[x].l, tree[y].l, l, mid);
merge(tree[x].r, tree[y].r, mid + 1, r);
push_up(x);
}
void dfs1(int u) {
sz[u] = 1; son[u] = 0;
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (v != fa[u]) {
fa[v] = u;
dep[v] = dep[u] + 1;
dfs1(v);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
}
void dfs2(int u, int tp, int x) {
top[u] = tp; w[u] = ++cnt; W[cnt] = u;
if (son[u]) dfs2(son[u], tp, 1);
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (v == son[u] || v == fa[u]) continue;
dfs2(v, v, 2);
}
}
int LCA(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) std::swap(x, y);
x = fa[top[x]];
}
if (dep[x] > dep[y]) std::swap(x, y);
return x;
}
int ans[maxn];
void dfs(int u, int fa) {
for(int i = head[u]; i != -1; i = edge[i].nxt) {
int v = edge[i].v;
if(v == fa) continue;
dfs(v, u);
merge(root[u], root[v], 1, 100000);
}
ans[u] = tree[root[u]].val;
}
int main() {
#ifndef ONLINE_JUDGE
FIN
#endif
int n, m;
init();
scanf("%d%d", &n, &m);
for(int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
add_edge(u, v);
add_edge(v, u);
}
dfs1(1);
dfs2(1, 1, 1);
for(int i = 1; i <= m; i++) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
int lca = LCA(x, y);
update(root[x], 1, 100000, z, 1);
// bug;
update(root[y], 1, 100000, z, 1);
update(root[lca], 1, 100000, z, -1);
if(fa[lca]) update(root[fa[lca]], 1, 100000, z, -1);
}
dfs(1, 0);
for(int i = 1; i <= n; i++) {
printf("%d\n", ans[i]);
}
return 0;
}
每一个不曾刷题的日子
都是对生命的辜负
从弱小到强大,需要一段时间的沉淀,就是现在了
~buerdepepeqi