基本都要用到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; }