|poj 2763|LCA, 树状数组|或者|树链剖分, 线段树|Housewife Wind
2017-05-09 20:12
351 查看
poj 2763
LCA+树状数组/线段树。
首先本题大致一看就是一个LCA,但是本题有操作更改某边的权,这样会使得原本的far数组变化,不难发现,更改边权后影响该边下面所有点的答案。此时可以在LCA的DFS预处理时求出DFS序列(即时间戳),找到每个点管辖的范围,修改边权相当于修改该边连接的两个点深度深的那个点所管辖的范围,此时修改可以用暴力,但是由于far数组与LCA本身查询无关,我们可以用数据结构进行维护far数组,树状数组/线段树都可以
树链剖分+线段树也可以。(此题卡vector,这迫使我试了一次链式前向星)
LCA+树状数组/线段树。
首先本题大致一看就是一个LCA,但是本题有操作更改某边的权,这样会使得原本的far数组变化,不难发现,更改边权后影响该边下面所有点的答案。此时可以在LCA的DFS预处理时求出DFS序列(即时间戳),找到每个点管辖的范围,修改边权相当于修改该边连接的两个点深度深的那个点所管辖的范围,此时修改可以用暴力,但是由于far数组与LCA本身查询无关,我们可以用数据结构进行维护far数组,树状数组/线段树都可以
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define ms(i, j) memset(i, j, sizeof i) #define FN2 "poj2763" using namespace std; const int MAXN = 100000 + 5, logs = 17; int n, q, s, wi[MAXN], deep[MAXN], pre[MAXN][logs+1], far[MAXN], ll[MAXN], rr[MAXN], cnt, a[MAXN], b[MAXN], Sc[MAXN]; vector<int> G[MAXN]; //bit int lowbit(int x) { return x&(-x); } void update(int x, int v) { for (int i=x;i<=n;i+=lowbit(i)) { far[i] += v; } } int dist(int x) { int ret = 0; for (int i=x;i>0;i-=lowbit(i)) { ret += far[i]; } return ret; } //lca void dfs(int x, int p) { ll[x] = ++cnt; Sc[x] = cnt; pre[x][0] = p; deep[x] = deep[p] + 1; for (int i=1;i<=logs;i++) pre[x][i] = pre[pre[x][i-1]][i-1]; for (int i=0;i<G[x].size();i++) { int u = G[x][i]; if (u!=p) { dfs(u, x); } } rr[x] = cnt; } int lca(int x, int y) { if (deep[x]>deep[y]) swap(x, y); int del = deep[y] - deep[x]; for (int i=logs;i>=0;i--) if ((del>>i) &1) y = pre[y][i]; if (x==y) return x; for (int i=logs;i>=0;i--) if (pre[x][i]!=pre[y][i]) x = pre[x][i], y = pre[y][i]; return pre[x][0]; } //pro void init() { cnt = 0; for (int i=1;i<=n;i++) { G[i].clear(), deep[i] = far[i] = ll[i] = rr[i] = 0; for (int j=0;j<=logs;j++) pre[i][j] = 0; } for (int i=1;i<n;i++) { scanf("%d%d%d", &a[i], &b[i], &wi[i]); G[a[i]].push_back(b[i]); G[b[i]].push_back(a[i]); } } void solve() { dfs(1, 0); int db4; for (int i=1;i<n;i++) { int x = a[i], y = b[i]; if (deep[x]>deep[y]) swap(x, y); update(ll[y], wi[i]); update(rr[y]+1, -wi[i]); } for (int i=1;i<=q;i++) { int opr; scanf("%d", &opr); if (opr==0) { int u; scanf("%d", &u); printf("%d\n", dist(Sc[s])+dist(Sc[u])-2*dist(Sc[lca(s, u)]));//一定要找s,u在DFS序列中的位置 s = u; } else { int x, w; scanf("%d%d", &x, &w); int y = (deep[a[x]]>deep[b[x]]) ? a[x] : b[x]; update(ll[y], w-wi[x]); update(rr[y]+1, wi[x]-w); wi[x] += w-wi[x];//边权点权分清楚 } } } int main() { #ifndef ONLINE_JUDGE freopen(FN2".in","r",stdin); freopen(FN2".out","w",stdout); #endif while (scanf("%d%d%d", &n, &q, &s)==3) { init(); solve(); } return 0; }
树链剖分+线段树也可以。(此题卡vector,这迫使我试了一次链式前向星)
#include<cstdio> #include<cstring> #include<algorithm> #define fo(i, j, k) for (i=(j);i<=(k);i++) #define fd(i, k, j) for (i=(k);i>=(j);i--) #define rd(a) scanf("%d", &a) #define rd2(a, b) scanf("%d%d", &a, &b) #define rd3(a, b, c) scanf("%d%d%d", &a, &b, &c) #define ms(i, j) memset(i, j, sizeof i) #define FN2 "poj2763" using namespace std; const int MAXN = 100001 + 5; struct data{int to, next;}e[MAXN*2]; int head[MAXN],cnt; int n, q, s, ai[MAXN], bi[MAXN], wi[MAXN]; int dep[MAXN], fa[MAXN], son[MAXN], siz[MAXN], p[MAXN], top[MAXN], pre; void ins(int u, int v) {cnt++, e[cnt].to = v, e[cnt].next = head[u],head[u] = cnt;} void dfs1(int u, int p) { int i; dep[u] = dep[p] + 1, fa[u] = p, siz[u] = 1; for (i=head[u];i!=-1;i=e[i].next) { int v = e[i].to; if (v!=p) { dfs1(v, u); siz[u] += siz[v]; if (son[u]==-1||siz[son[u]]<siz[v]) son[u] = v; } } } void dfs2(int u, int chain) { int i; top[u] = chain, p[u] = ++pre; if (son[u]!=-1) { dfs2(son[u], chain); for (i=head[u];i!=-1;i=e[i].next) { int v = e[i].to; if (v!=fa[u]&&v!=son[u]) dfs2(v, v); } } } int sumv[MAXN*4]; void pushup(int o) { int lc = o*2, rc = o*2+1; sumv[o] = sumv[lc] + sumv[rc]; } void update(int o, int l, int r, int x, int y, int v) { int lc = o*2, rc = o*2+1, M = (l+r)/2; if (x<=l&&r<=y) { sumv[o] = v; return ; } if (x<=M) update(lc, l, M, x, y, v); if (M<y) update(rc, M+1, r, x, y, v); pushup(o); } int query(int o, int l, int r, int x, int y) { int lc = o*2, rc = o*2+1, M = (l+r)/2, ret = 0; if (x<=l&&r<=y) { return sumv[o]; } if (x<=M) ret += query(lc, l, M, x, y); if (M<y) ret += query(rc, M+1, r, x, y); return ret; } int findSUM(int u, int v) { int f1 = top[u], f2 = top[v], ret = 0; while (f1!=f2) { if (dep[f1]<dep[f2]) swap(f1, f2), swap(u, v); ret += query(1,1,n,p[f1],p[u]); u = fa[f1]; f1 = top[u]; } if (dep[u]<dep[v]) swap(u, v); return ret + query(1,1,n,p[v]+1,p[u]); } void init() { int i; pre = 0; fo (i, 1, n) dep[i] = fa[i] = siz[i] = p[i] = top[i] = 0, son[i] = -1, head[i] = e[i].next = -1; fo (i, 1, n*4) sumv[i] = 0; fo (i, 1, n-1) { rd3(ai[i], bi[i], wi[i]); ins(ai[i], bi[i]), ins(bi[i], ai[i]); } dfs1(1, 0), dfs2(1, 1); fo (i, 1, n-1) { int a1 = ai[i], b1 = bi[i]; if (dep[a1]>dep[b1]) update(1, 1, n, p[a1], p[a1], wi[i]); if (dep[a1]<dep[b1]) update(1, 1, n, p[b1], p[b1], wi[i]); } } void solve() { int i; fo (i, 1, q) { int opt; rd(opt); if (opt==0) { int u; rd(u); printf("%d\n", findSUM(u, s)); s = u; } else { int u, w; rd2(u, w); int a1 = ai[u], b1 = bi[u]; if (dep[a1]>dep[b1]) update(1, 1, n, p[a1], p[a1], w); if (dep[a1]<dep[b1]) update(1, 1, n, p[b1], p[b1], w); } } } int main() { #ifndef ONLINE_JUDGE freopen(FN2".in","r",stdin);freopen(FN2".out","w",stdout); #endif while (rd3(n, q, s)==3) init(), solve(); return 0; }
相关文章推荐
- poj 2763 Housewife Wind 【LCA 与 树状数组】
- LCA+树状数组 POJ 2763 Housewife Wind
- POJ 2763 Housewife Wind [树链剖分(边权)+树状数组]【数据结构】
- POJ-2763 Housewife Wind (树链剖分 入门题 树状数组 单点修改 区间查询)
- POJ 2763 Housewife Wind(树链剖分)(线段树单点修改)
- POJ 2763 Housewife Wind (LCA+线段树)
- POJ 2763 Housewife Wind(树链剖分+线段树点更新-区间查询+入边)
- POJ 2763 Housewife Wind LCA转RMQ+时间戳+线段树成段更新
- POJ 2763 树链剖分 线段树 Housewife Wind
- poj2763 Housewife Wind【树链剖分+线段树】
- POJ - 2763 Housewife Wind(LCA+暴力)
- POJ-2763 Housewife Wind(树链剖分)
- POJ 2763 Housewife Wind (树链剖分)
- 【树链剖分】 POJ 2763 Housewife Wind 边权
- POJ 2763 Housewife Wind (树链剖分)
- poj 2763 Housewife Wind 树链剖分
- POJ 2763 -- Housewife Wind 树链剖分 LCT 动态树
- POJ 2763 Housewife Wind (LCA+树状数组)
- POJ 2763 Housewife Wind 树链剖分
- POJ 2763 Housewife Wind 树链剖分