线段树合并训练记录
[POI2011]ROT-Tree Rotations
#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <string.h>
#include <map>
#include <iostream>
using namespace std;
const int maxn = 4e6 + 50;
const int mod = 20090717;
typedef long long LL;
int INF = 1e9;
typedef pair<int, int> pii;
#define fi first
#define se second
int n;
struct node
{
int lc, rc;
LL val;
} tree[maxn];
int tot = 1;
int Build(){
tot++;
tree[tot].lc = tree[tot].rc = 0;
tree[tot].val = 0;
return tot;
}
int insert(int le, int ri, int pos){
tree[++tot].val = 1;
if(le == ri){
return tot;
}
int mid = (le + ri) >> 1;
int rt = tot;
if(pos <= mid) tree[rt].lc = insert(le, mid, pos);
else tree[rt].rc = insert(mid + 1, ri, pos);
return rt;
}
LL ans, ans1, ans2;
int merage(int le, int ri, int u, int v){
if(!u || !v) return u | v;
if(le == ri) {
tree[u].val += tree[v].val;
return u;
}
int mid = (le + ri) >> 1;
ans1 += tree[tree[u].lc].val * tree[tree[v].rc].val;
ans2 += tree[tree[u].rc].val * tree[tree[v].lc].val;
tree[u].lc = merage(le, mid, tree[u].lc, tree[v].lc);
tree[u].rc = merage(mid + 1, ri, tree[u].rc, tree[v].rc);
tree[u].val = tree[tree[u].lc].val + tree[tree[u].rc].val;
return u;
}
int dfs(){
int u;
scanf("%d", &u);
if(u) return insert(1, n, u);
int rt = merage(1, n, dfs(), dfs());
// printf("ans1 = %I64d ans2 = %I64d\n", ans1, ans2);
ans += min(ans1, ans2);
ans1 = ans2 = 0;
return rt;
}
int main(int argc, char const *argv[])
{
scanf("%d", &n);
dfs();
printf("%lld\n", ans);
return 0;
}
洛谷:P4556 [Vani有约会]雨天的尾巴
题解:树上差分 + 线段树合并
#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <string.h>
#include <map>
#include <iostream>
#include <math.h>
using namespace std;
const int maxn = 6e6 + 50;
const int mod = 20090717;
typedef long long LL;
int INF = 1e9;
typedef pair<int, int> pii;
#define fi first
#define se second
int n, m;
int nn = 1e5 + 50;
struct node
{
int lc, rc;
int val;
} tree[maxn];
vector<int> vec[maxn], vec2[maxn];
int tot;
int Build(){
tot++;
tree[tot].lc = tree[tot].rc = 0;
tree[tot].val = 0;
return tot;
}
int root[maxn];
int insert(int le, int ri, int pos, int val, int rt){
if(le == ri){
tree[rt].val += val;
return rt;
}
int mid = (le + ri) >> 1;
if(pos <= mid) {
if(tree[rt].lc == 0) tree[rt].lc = Build();
tree[rt].lc = insert(le, mid, pos, val, tree[rt].lc);
}
else {
if(tree[rt].rc == 0) tree[rt].rc = Build();
tree[rt].rc = insert(mid + 1, ri, pos, val, tree[rt].rc);
}
tree[rt].val = max(tree[tree[rt].lc].val, tree[tree[rt].rc].val);
return rt;
}
int merage(int le, int ri, int u, int v){
if(!u || !v) return u | v;
if(le == ri) {
tree[u].val += tree[v].val;
return u;
}
int mid = (le + ri) >> 1;
tree[u].lc = merage(le, mid, tree[u].lc, tree[v].lc);
tree[u].rc = merage(mid + 1, ri, tree[u].rc, tree[v].rc);
tree[u].val = max(tree[tree[u].lc].val, tree[tree[u].rc].val);
return u;
}
int Query(int le, int ri, int rt){
if(!rt) return 0;
if(le == ri){
return le;
}
if(tree[rt].val == 0) return 0;
int mid = (le + ri) >> 1;
if(tree[tree[rt].lc].val >= tree[tree[rt].rc].val){
return Query(le, mid, tree[rt].lc);
} else {
return Query(mid + 1, ri, tree[rt].rc);
}
}
struct Edge
{
int to, next;
} edge[maxn];
int head[maxn], k;
void add(int a, int b){
edge[k].to = b;
edge[k].next = head[a];
head[a] = k++;
}
int ans[maxn];
void dfs(int u, int pre){
root[u] = Build();
for(int i = head[u]; i != -1; i = edge[i].next){
int to = edge[i].to;
if(to == pre) continue;
dfs(to, u);
merage(1, nn, root[u], root[to]);
}
if(vec[u].size()){
int len = vec[u].size();
for(int i = 0; i < len; i++){
int val = 1;
if(vec[u][i] < 0) val = -1;
insert(1, nn, abs(vec[u][i]), val, root[u]);
}
}
ans[u] = Query(1, nn, root[u]);
}
int fa[maxn][30], depth[maxn];
void dfs2(int u, int pre, int d){
fa[u][0] = pre, depth[u] = d;
for(int i = head[u]; i != -1; i = edge[i].next){
int to = edge[i].to;
if(to == pre) continue;
dfs2(to, u, d + 1);
}
}
void init(int root){
dfs2(root, 0, 0);
for(int j = 0; (1 << (j + 1)) < n; j++){
for(int i = 1; i <= n; i++){
if(fa[i][j] == 0) fa[i][j + 1] = 0;
else fa[i][j + 1] = fa[fa[i][j]][j];
}
}
}
int LCA(int u, int v){
if(depth[u] > depth[v]) swap(u, v);
int temp = depth[v] - depth[u];
for(int i = 0; (1 << i) <= temp; i++){
if((1 << i) & temp) v = fa[v][i];
}
if(v == u) return u;
for(int i = log2(n); i >= 0; i--){
if(fa[u][i] != fa[v][i]){
u = fa[u][i], v = fa[v][i];
}
}
return fa[u][0];
}
int main(int argc, char const *argv[])
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) head[i] = -1;
for(int i = 1; i < n; i++){
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
init(1);
for(int i = 1; i <= m; i++){
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
vec[x].push_back(z);
vec[y].push_back(z);
int lcaxy = LCA(x, y);
vec[lcaxy].push_back(-z);
vec[fa[lcaxy][0]].push_back(-z);
}
dfs(1, 0);
for(int i = 1; i <= n; i++){
printf("%d\n", ans[i]);
}
return 0;
}
BZOJ 3545. [ONTAK2010]Peaks
题解:并查集 + 线段树合并,每次用线段树维护一个联通块
注:由于存在相同高度,所以要合并的两颗线段树可能存在相同的叶子节点,所以要对叶子节点特殊处理,否则会 \(wa\) 到爆炸
#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <string.h>
#include <map>
#include <iostream>
#include <math.h>
using namespace std;
const int maxn = 1e5 + 50;
const int MA = 1e7 + 50;
const int mod = 20090717;
typedef long long LL;
int INF = 1e9;
typedef pair<int, int> pii;
#define fi first
#define se second
int n, m;
struct node
{
int lc, rc;
int val;
} tree[MA];
int a[maxn], lsh[maxn], id[maxn];
int tot;
int root[maxn];
int fa[maxn];
int Find(int x){
if(x == fa[x]) return x;
return fa[x] = Find(fa[x]);
}
struct Edge
{
int u, v, w;
int id;
bool operator < (const Edge &r) const{
return w < r.w;
}
} edge[5 * maxn], quer[5 * maxn];
void insert(int le, int ri, int pos, int &rt){
if(!rt) rt = ++tot;
tree[rt].val = 1;
if(le == ri) return ;
int mid = (le + ri) >> 1;
if(pos <= mid) insert(le, mid, pos, tree[rt].lc);
else insert(mid + 1, ri, pos, tree[rt].rc);
}
int imerage(int le, int ri, int u, int v){
if(!u || !v) return u | v;
if(le == ri) { // 这句一定要加上,否则相同的叶子节点不会合并,因为数据存在相同的高度
tree[u].val += tree[v].val;
return u;
}
// if(!tree[u].lc && !tree[u].rc){
// tree[u].val += tree[v].val;
// return u;
// }
int mid = (le + ri) >> 1;
tree[u].lc = imerage(le, mid, tree[u].lc, tree[v].lc);
tree[u].rc = imerage(mid + 1, ri, tree[u].rc, tree[v].rc);
tree[u].val = tree[tree[u].lc].val + tree[tree[u].rc].val;
return u;
}
int Query(int le, int ri, int rt, int sum){
if(tree[rt].val < sum) return 0;
if(le == ri) return le;
int mid = (le + ri) >> 1;
if(tree[tree[rt].rc].val >= sum) {
return Query(mid + 1, ri, tree[rt].rc, sum);
} else {
return Query(le, mid, tree[rt].lc, sum - tree[tree[rt].rc].val);
}
}
int ans[5 * maxn];
int main(int argc, char const *argv[])
{
int q;
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= n; i++){
fa[i] = i;
scanf("%d", &a[i]);
lsh[i] = a[i];
}
sort(lsh + 1, lsh + n + 1);
int cnt;
for(int i = 1; i <= n; i++){
a[i] = lower_bound(lsh + 1, lsh + n + 1, a[i]) - lsh;
}
for(int i = 1; i <= m; i++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edge[i] = {u, v, w, 0};
}
for(int i = 1; i <= q; i++){
int u, x, k;
scanf("%d%d%d", &u, &x, &k);
quer[i] = {u, k, x, i};
}
sort(edge + 1, edge + m + 1);
sort(quer + 1, quer + q + 1);
cnt = 1;
for(int i = 1; i <= n; i++) insert(1, n, a[i], root[i]);
lsh[0] = -1;
for(int i = 1; i <= q; i++){
while(edge[cnt].w <= quer[i].w && cnt <= m){
int u = edge[cnt].u, v = edge[cnt].v;
u = Find(u), v = Find(v); // 这里写成fa[u], fa[v] 会MLE
if(u == v){
cnt++;
continue;
}
imerage(1, n, root[u], root[v]);
fa[v] = u;
cnt++;
}
int u = quer[i].u;
u = Find(u);
int res = Query(1, n, root[u], quer[i].v);
ans[quer[i].id] = lsh[res];
}
for(int i = 1; i <= q; i++){
printf("%d\n", ans[i]);
}
return 0;
}