五道线段树题目(树上操作)

基本都要用到dfs序,转为序列操作。

(一)codeforces620E New Year Tree

子树颜色种类统计,考虑到最多60种颜色,采用位运算或来保存当前颜色状态即可。

#include <cstdio>
#define N 400010
typedef long long ll;
struct edge {int to, next;}e[N<<1];
int c[N], head[N], st[N], ed[N], rid[N];
int n, m, dfn = 0, cnt = 1;
inline void ins(int x, int y) {e[++cnt].to = y; e[cnt].next = head[x]; head[x] = cnt;}
void dfs(int x, int f) {
	st[x] = ++dfn; rid[dfn] = x;
	for(int i = head[x]; i; i = e[i].next) if(e[i].to != f) dfs(e[i].to, x);
	ed[x] = dfn;
}
struct segtree {int l, r, tag; ll cor;}t[N<<2];
void build(int p, int l, int r) {
	t[p].l = l; t[p].r = r; t[p].tag = -1; t[p].cor = 0;
	if(l == r) {t[p].cor = 1ll<<(c[rid[l]]); return ;}
	int mid = (l + r)>>1;
	build(p<<1, l, mid); build(p<<1|1, mid + 1, r);
	t[p].cor = t[p<<1].cor|t[p<<1|1].cor;
}
inline void pushdown(int p) {
	if(t[p].tag != -1) {
		t[p<<1].tag = t[p<<1|1].tag = t[p].tag;
		t[p<<1].cor = t[p<<1|1].cor = 1ll<<t[p].tag;
		t[p].tag = -1;
	}
}
void change(int p, int l, int r, int cor) {
	if(l <= t[p].l && t[p].r <= r) {t[p].tag = cor; t[p].cor = 1ll<<cor; return ;}
	pushdown(p); int mid = (t[p].l + t[p].r)>>1;
	if(l <= mid) change(p<<1, l, r, cor);
	if(mid + 1 <= r) change(p<<1|1, l, r, cor);
	t[p].cor = t[p<<1].cor|t[p<<1|1].cor;
}
ll ans = 0;
void query(int p, int l, int r) {
	if(l <= t[p].l && t[p].r <= r) {ans|= t[p].cor; return ;}
	pushdown(p); int mid = (t[p].l + t[p].r)>>1;
	if(l <= mid) query(p<<1, l, r);
	if(mid + 1 <= r) query(p<<1|1, l, r);
}
int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i) {scanf("%d", c+i); --c[i];}
	for(int i = 1; i < n; ++i) {int x, y; scanf("%d%d", &x, &y); ins(x, y); ins(y, x);}
	dfs(1, 1); build(1, 1, n);
	for(int i = 1; i <= m; ++i) {
		int opt; scanf("%d", &opt);
		if(opt == 1) {
			int x, cor; scanf("%d%d", &x, &cor); --cor;
			change(1, st[x], ed[x], cor);
		}else {
			int x; scanf("%d", &x);
			query(1, st[x], ed[x]);
			int num = 0; for(; ans; ans-= ans & -ans) ++num;
			printf("%d\n", num);
		}
	}
	return 0;
}

(二)codeforces384E Propagating tree

当对一个点进行+x,其奇数层儿子要-x,偶数层儿子要+x。

直接染色1与-1,剩下的与正常线段树一般无二。

#include <cstdio>
#define N 200010
struct edge {int to, next;}e[N<<1];
int a[N], head[N], st[N], ed[N], rid[N], dep[N];
int n, m, dfn = 0, cnt = 1;
inline void ins(int x, int y) {e[++cnt].to = y; e[cnt].next = head[x]; head[x] = cnt;}
void dfs(int x, int f) {
	st[x] = ++dfn; rid[dfn] = x;
	for(int i = head[x]; i; i = e[i].next) if(e[i].to != f) {dep[e[i].to] = dep[x] + 1; dfs(e[i].to, x);}
	ed[x] = dfn;
}
struct segtree {int l, r, tag, fh;}t[N<<2];
void build(int p, int l, int r) {
	t[p].l = l; t[p].r = r; t[p].tag = 0;
	if(l != r) {int mid = (l + r)>>1; build(p<<1, l, mid); build(p<<1|1, mid + 1, r);}
}
void change(int p, int l, int r, int val) {
	if(l <= t[p].l && t[p].r <= r) {t[p].tag+= val; return ;}
	int mid = (t[p].l + t[p].r)>>1;
	if(l <= mid) change(p<<1, l, r, val);
	if(mid + 1 <= r) change(p<<1|1, l, r, val);
}
inline void pushdown(int p) {t[p<<1].tag+= t[p].tag; t[p<<1|1].tag+= t[p].tag; t[p].tag = 0;}
int query(int p, int x) {
	if(t[p].l == t[p].r) return a[rid[t[p].l]] + t[p].tag * ((dep[rid[t[p].l]] & 1)?1:(-1));
	pushdown(p); int mid = (t[p].l + t[p].r)>>1;
	if(x <= mid) return query(p<<1, x); else return query(p<<1|1, x);
}
int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i) scanf("%d", a+i);
	for(int i = 1; i < n; ++i) {int x, y; scanf("%d%d", &x, &y); ins(x, y); ins(y, x);}
	dep[1] = 1; dfs(1, 1); build(1, 1, n);
	for(int i = 1; i <= m; ++i) {
		int opt, x; scanf("%d%d", &opt, &x);
		if(opt == 1) {
			int val; scanf("%d", &val); val*= (dep[x] & 1)?1:(-1);
			change(1, st[x], ed[x], val);
		}else printf("%d\n", query(1, st[x]));
	}	
	return 0;
}

(三)codeforces838B

给一个性质极特殊的图,求动态两点最短路。画个图看一下就出来了。

#include <cstdio>
#include <algorithm>
#define N 200010
using namespace std;
typedef long long ll;
inline char gc() {
	static char now[1<<16], *S, *T;
	if(S == T) {T = (S = now) + fread(now, 1, 1<<16, stdin); if(S == T) return EOF;}
	return *S++;
}
inline int read() {
	int x = 0; char c = gc();
	while(c < '0' || c > '9') c = gc();
	while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = gc();}
	return x;
}
struct edge {int to, val, next;}e[N<<1];
int head[N], st[N], ed[N], rid[N], fr[N];
ll val1[N], val2[N];
int n, q, dfn = 0, cnt = 0;
inline void ins(int x, int y, int z) {e[++cnt].to = y; e[cnt].val = z; e[cnt].next = head[x]; head[x] = cnt;}
void dfs(int x, int f) {
	st[x] = ++dfn; rid[dfn] = x;
	for(int i = head[x]; i; i = e[i].next) if(e[i].to != f) {val1[e[i].to] = val1[x] + e[i].val; dfs(e[i].to, x);}
	ed[x] = dfn;
}
int belong[N];
struct segtree {int l, r; ll v1, v2, tag;}t[N<<2];
inline void update(int p) {t[p].v2 = min(t[p<<1].v2, t[p<<1|1].v2);}
inline void pushdown(int p) {
	t[p<<1].tag+= t[p].tag; t[p<<1|1].tag+= t[p].tag;
	t[p<<1].v1+= t[p].tag; t[p<<1|1].v1+= t[p].tag;
	t[p<<1].v2+= t[p].tag; t[p<<1|1].v2+= t[p].tag;
	t[p].tag = 0;
}
void build(int p, int l, int r) {
	t[p].l = l; t[p].r = r; t[p].tag = 0;
	if(l == r) {
		int now = rid[l];
		t[p].v1 = val1[now]; t[p].v2 = val2[now]; belong[now] = p;
		return ;
	}
	int mid = (l + r)>>1; build(p<<1, l, mid); build(p<<1|1, mid + 1, r); update(p);
}
void add(int p, int l, int r, ll x) {
	if(l <= t[p].l && t[p].r <= r) {t[p].tag+= x; t[p].v2+= x; t[p].v1+= x; return ;}
	pushdown(p);
	int mid = (t[p].l + t[p].r)>>1;
	if(l <= mid) add(p<<1, l, r, x);
	if(mid + 1 <= r) add(p<<1|1, l, r, x);
	update(p);
}
void add2(int p, int pos, ll x) {
    if(t[p].l == t[p].r) {t[p].v2+= x; return ;}
    pushdown(p);
    int mid = (t[p].l + t[p].r)>>1;
    if(pos <= mid) add2(p<<1, pos, x); else add2(p<<1|1, pos, x);
    update(p);
}
ll getval1(int p, int x) {
	if(t[p].l == t[p].r) return t[p].v1;
	pushdown(p); int mid = (t[p].l + t[p].r)>>1;
	if(x <= mid) return getval1(p<<1, x);
	else return getval1(p<<1|1, x);
}
ll getval2(int p, int l, int r) {
	if(l <= t[p].l && t[p].r <= r) return t[p].v2;
	pushdown(p); int mid = (t[p].l + t[p].r)>>1;
	ll s1 = (ll)2e12, s2 = (ll)2e12;
	if(l <= mid) s1 = getval2(p<<1, l, r);
	if(mid + 1 <= r) s2 = getval2(p<<1|1, l, r);
	return min(s1, s2);
}
int main() {
	n = read(); q = read();
	for(int i = 1; i < n; ++i) {int x = read(), y = read(), z = read(); ins(x, y, z);}
	val1[1] = 0; dfs(1, 1);
	for(int i = 1; i < n; ++i) {int x = read(), y = read(), z = read(); ins(x, y, z); val2[x] = val1[x] + z; fr[i] = x;}
	build(1, 1, n);
	for(int i = 1; i <= q; ++i) {
		int opt = read(), x = read(), y = read();
		if(opt == 1) {
			if(x <= n - 1) {
				int to = e[x].to;
				add(1, st[to], ed[to], y - e[x].val); e[x].val = y;
			}else {
				int from = fr[x - n + 1];
				add2(1, st[from], y - e[x].val);
				e[x].val = y;
			}
		}else {
			if(st[x] <= st[y] && ed[y] <= ed[x]) printf("%I64d\n", getval1(1, st[y]) - getval1(1, st[x]));
			else {
				ll ans = getval1(1, st[y]) + getval2(1, st[x], ed[x]) - getval1(1, st[x]);
				printf("%I64d\n", ans);
			}
		}
	}
	return 0;
}

(四)Hdu3974 Assign the Task

直接搞一下dfs序就好,挺裸的。

(五)bzoj4034

扫描二维码关注公众号,回复: 962403 查看本文章

树链剖分处理子树。其实树链剖分无非就是给dfs序又调整了一下顺序而已,使得复杂度最低化。换言之,如果把边按某种方法调整,id就是直接dfs得到的dfs序。可以用BIT或线段树维护部分和。

#include <cstdio>
#define N 100010
typedef long long ll;
inline char gc() {
    static char now[1<<16], *S, *T;
    if(S == T) {T = (S = now) + fread(now, 1, 1<<16, stdin); if(S == T) return EOF;}
    return *S++;
}
inline int read() {
    int x = 0, f = 1; char c = gc();
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = gc();}
    while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = gc();}
    return x * f;
}
struct edge {int to, next;}e[N<<1];
int val[N], head[N], sz[N], son[N], dep[N], fa[N], tp[N], id[N], rid[N], ed[N];
int n, m, cnt = 1, len = 0;
inline void ins(int x, int y) {e[++cnt].to = y; e[cnt].next = head[x]; head[x] = cnt;}
void dfs1(int x, int f, int d) {
    dep[x] = d; fa[x] = f; sz[x] = 1; son[x] = 0;
    for(int i = head[x]; i; i = e[i].next) {
        int y = e[i].to; if(y == f) continue;
        dfs1(y, x, d + 1); sz[x]+= sz[y];
        if(!son[x] || sz[y] > sz[son[x]]) son[x] = y;
    }
}
void dfs2(int x, int f) {
    tp[x] = f; id[x] = ++len; rid[len] = x; ed[x] = len;
    if(!son[x]) return ;
    dfs2(son[x], f);
    for(int i = head[x]; i; i = e[i].next) {
        int y = e[i].to;
        if(y != son[x] && y != fa[x]) dfs2(y, y);
    }ed[x] = len;
}
struct segtree {int l, r; ll tag, v;}t[N<<2];
inline void pushdown(int p) {
    int l = t[p].l, r = t[p].r;
    int mid = (t[p].l + t[p].r)>>1;
    t[p<<1].tag+= t[p].tag; t[p<<1|1].tag+= t[p].tag;
    t[p<<1].v+= t[p].tag * (mid - l + 1); t[p<<1|1].v+= t[p].tag * (r - mid); t[p].tag = 0;
}
void build(int p, int l, int r) {
    t[p].l = l; t[p].r = r; t[p].tag = 0;
    if(l == r) {t[p].v = val[rid[l]]; return ;}
    int mid = (l + r)>>1;
    build(p<<1, l, mid); build(p<<1|1, mid + 1, r);
    t[p].v = t[p<<1].v + t[p<<1|1].v;
}
void add(int p, int l, int r, ll delta) {
    if(l <= t[p].l && t[p].r <= r) {t[p].tag+= delta; t[p].v+= delta * (t[p].r - t[p].l + 1); return ;}
    pushdown(p); int mid = (t[p].l + t[p].r)>>1;
    if(l <= mid) add(p<<1, l, r, delta);
    if(mid + 1 <= r) add(p<<1|1, l, r, delta);
    t[p].v = t[p<<1].v + t[p<<1|1].v;
}
ll query(int p, int l, int r) {
    if(l <= t[p].l && t[p].r <= r) return t[p].v;
    pushdown(p); int mid = (t[p].l + t[p].r)>>1;
    ll ret = 0;
    if(l <= mid) ret+= query(p<<1, l, r);
    if(mid + 1 <= r) ret+= query(p<<1|1, l, r);
    return ret;
}
inline ll asksum(int x) {
    ll ret = 0;
    while(tp[x] != 1) {ret+= query(1, id[tp[x]], id[x]); x = fa[tp[x]];}
    ret+= query(1, id[1], id[x]);
    return ret;
}
int main() {
    n = read(); m = read();
    for(int i = 1; i <= n; ++i) val[i] = read();
    for(int i = 1; i < n; ++i) {int fr = read(), to = read(); ins(fr, to); ins(to, fr);}
    dfs1(1, 0, 1); dfs2(1, 1); build(1, 1, n);
    for(int i = 1; i <= m; ++i) {
        int opt = read(), x = read();
        if(opt == 1) {int v = read(); add(1, id[x], id[x], v);}
        if(opt == 2) {int v = read(); add(1, id[x], ed[x], v);}
        if(opt == 3) printf("%lld\n", asksum(x));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/richard_for_oi/article/details/80313552