POJ 2763 Housewife Wind
来源:互联网 发布:新浪体育英超数据库 编辑:程序博客网 时间:2024/05/16 06:44
题意: 知道了一颗有 n 个节点的树和树上每条边的权值,对应两种操作:
【LCA_RMQ+树状数组】
0 x 输出 当前节点到 x节点的最短距离,并移动到 x 节点位置 1 x val 把第 x 条边的权值改为 val
分析: 树上两个节点a,b的距离可以转化为
dis[a] + dis[b] - 2*dis[lca(a,b)] 其中 dis[i] 表示 i 节点到根的距离, 由于每次修改一条边,树中在这条边下方的 dis[] 值全都会受到影响,这样每条边都对应这一段这条边的管辖区, 可以深搜保存遍历该点的时间戳,ll[i] 表示第一次遍历到该点的时间戳, rr[i] 表示回溯到该点时的时间戳,这样每次 修改边 i 的时候就可以对区间 [ ll[i], rr[i] ] 进行成段更新,成段更新的方式可以在 位置 ll[i] 上加一个权值,在位置 rr[i]+1 上减去这个权值,求和时,sum(ll[i]) 即为该点到根的距离。
#include<stdio.h>#include<string.h>#include<math.h>#define clr(x)memset(x,0,sizeof(x))#define maxn 200005struct node{ int to,next,w,xu;}e[1000000];int tot;int head[maxn];void add(int s,int t,int wi,int xu){ e[tot].xu=xu; e[tot].w=wi; e[tot].to=t; e[tot].next=head[s]; head[s]=tot++;}int dp[maxn<<1][18];int x[maxn<<1];int d[maxn];int r[maxn];int v[maxn];int f[maxn];int ll[maxn];int rr[maxn];int g[maxn];int n,m;int min(int i,int j){ return d[i]<d[j]?i:j;}void makermq(int nn){ int i,j; for(i=0;i<nn;i++) dp[i][0]=i; for(j=1;(1<<j)<=nn;j++) for(i=1;i+(1<<j)-1<nn;i++) dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);}int rmq(int l,int r){ int k=(int)(log((r-l+1)*1.0)/log(2.0)); return min(dp[l][k],dp[r-(1<<k)+1][k]);}int cnt,ti;void dfs(int u,int deep){ v[u]=1; x[cnt]=u; d[cnt]=deep; r[u]=cnt++; ll[u]=++ti; int i,k; for(i=head[u];i;i=e[i].next) { k=e[i].to; if(!v[k]) { g[e[i].xu]=k; dfs(k,deep+1); x[cnt]=u; d[cnt++]=deep; } } rr[u]=ti;}int tree[maxn];int lowbit(int x){ return (x)&(-x);}void update(int pos,int x){ while(pos<=n) { tree[pos]+=x; pos+=lowbit(pos); }}int sum(int pos){ int s=0; while(pos>0) { s+=tree[pos]; pos-=lowbit(pos); } return s;}int edge[maxn];int val[maxn];int main(){ int i,st; while(scanf("%d%d%d",&n,&m,&st)!=EOF) { int a,b,c; clr(head); clr(v); clr(f); clr(tree); tot=1; ti=-1; for(i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); val[i]=c; edge[i]=c; add(a,b,c,i); add(b,a,c,i); } cnt=0; dfs(1,0); makermq(2*n-1); for(i=1;i<n;i++) { update(ll[g[i]],edge[i]); update(rr[g[i]]+1,-edge[i]); } int op; while(m--) { scanf("%d",&op); if(op==1) { scanf("%d%d",&a,&b); update(ll[g[a]],-val[a]); update(rr[g[a]]+1,val[a]); update(ll[g[a]],b); update(rr[g[a]]+1,-b); val[a]=b; } else { scanf("%d",&a); int lca,d1,d2,d3; if(r[st]<=r[a]) lca=x[rmq(r[st],r[a])]; else lca=x[rmq(r[a],r[st])]; d1=sum(ll[st]); d2=sum(ll[a]); d3=sum(ll[lca]); st=a; printf("%d\n",d1+d2-2*d3); } } } return 0;}
这个是利用线段树维护区间和,把边尾所涉及到的时间戳区间内的值都加上对应权值,然后某个点的值就代表了它到根节点的距离!!
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 200010;struct edge{ int u, v, w, next;}edges[maxn*2], e[maxn];int E[maxn*2], H[maxn*2], I[maxn*2], L[maxn], R[maxn];int dp[maxn*2][40];int cnt, clock, dfn;int first[maxn];int a[maxn<<2];int b[maxn];int add[maxn<<2];int degree[maxn];int vis[maxn];void AddEdge(int u, int v, int w){ edges[cnt].u = u; edges[cnt].v = v; edges[cnt].w = w; edges[cnt].next = first[u]; first[u] = cnt++; edges[cnt].u = v; edges[cnt].v = u; edges[cnt].w = w; edges[cnt].next = first[v]; first[v] = cnt++; }void dfs(int u, int fa, int dep){ E[++clock] = u; H[clock] = dep; I[u] = clock; L[u] = ++dfn; b[dfn] = u; for(int i = first[u]; i != -1; i = edges[i].next) { int v = edges[i].v; if(v == fa) continue; if(vis[v]) continue; vis[v] = true; dfs(v, u, dep+1); E[++clock] = u; H[clock] = dep; } R[u] = dfn;}void RMQ_init(int n){ for(int i = 1; i <= n; i++) dp[i][0] = i; for(int j = 1; (1<<j) <= n; j++) for(int i = 1; i+(1<<j)-1 <= n; i++) { if(H[dp[i][j-1]] < H[dp[i+(1<<(j-1))][j-1]]) dp[i][j] = dp[i][j-1]; else dp[i][j] = dp[i+(1<<(j-1))][j-1]; }}int RMQ(int l, int r){ l = I[l], r = I[r]; if(l > r) swap(l, r); int len = r-l+1, k = 0; while((1<<k) <= len) k++; k--; if(H[dp[l][k]] < H[dp[r-(1<<k)+1][k]]) return E[dp[l][k]]; else return E[dp[r-(1<<k)+1][k]];}void pushdown(int rt, int l, int r){ int k = (r-l+1); if(add[rt]) { a[rt<<1] += add[rt]*(k-(k>>1)); a[rt<<1|1] += add[rt]*(k>>1); add[rt<<1] += add[rt]; add[rt<<1|1] += add[rt]; add[rt] = 0; }}void build(int l, int r, int rt){ a[rt] = 0; add[rt] = 0; if(l == r) return; int m = (l + r) >> 1; build(l, m, rt<<1); build(m+1, r, rt<<1|1);}void update(int x, int y, int l, int r, int rt, int num){ if(l == x && r == y) { a[rt] += (r-l+1)*num; add[rt] += num; return; } pushdown(rt, l, r); int m = (l + r) >> 1; if(y <= m) update(x, y, l, m, rt<<1, num); else if(x > m) update(x, y, m+1, r, rt<<1|1, num); else { update(x, m, l, m, rt<<1, num); update(m+1, y, m+1, r, rt<<1|1, num); } a[rt] = a[rt<<1] + a[rt<<1|1];}int query(int x, int l, int r, int rt){ if(l == r) { return a[rt]; } pushdown(rt, l, r); int m = (l + r) >> 1; int ans = 0; if(x <= m) ans = query(x, l, m, rt<<1); else ans = query(x, m+1, r, rt<<1|1); a[rt] = a[rt<<1] + a[rt<<1|1]; return ans;}int main(){ int cas = 1; int T; //scanf("%d", &T); int s, to, root, n, q; while(scanf("%d %d %d", &n, &q, &s) != EOF) { memset(vis, 0, sizeof(vis)); memset(first, -1, sizeof(first)); memset(degree, 0, sizeof(degree)); clock = cnt = dfn = 0; build(1, n, 1); //for(int i = 1; i <= n; i++) // scanf("%d", &b[i]); for(int i = 1; i < n; i++) { int u, v, w; scanf("%d %d %d", &u, &v, &w); e[i].u = u; e[i].v = v; e[i].w = w; AddEdge(u, v, 0); degree[v]++; } for(int i = 1; i <= n; i++) if(!degree[i]) { vis[i] = true; dfs(i, -1, 0); root = i; break; } RMQ_init(2*n-1); //puts("1"); for(int i = 1; i < n; i++) { int u = e[i].u; int v = e[i].v; int w = e[i].w; //printf("***%d %d\n", L[v], R[v]); if(L[u] < L[v]) update(L[v], R[v], 1, n, 1, w); else update(L[u], R[u], 1, n, 1, w); } while(q--) { int x; scanf("%d", &x); if(!x) { scanf("%d", &to); int d1 = query(L[s], 1, n, 1); int d2 = query(L[to], 1, n, 1); int lca = RMQ(s, to); int d3 = query(L[lca], 1, n, 1); //printf("***%d %d %d\n", d1, d2, d3); printf("%d\n", d1+d2-2*d3); //printf("%d\n", dfn); s = to; } else { int i, w; scanf("%d %d", &i, &w); int x = w - e[i].w; e[i].w = w; int v = e[i].v; int u = e[i].u; if(L[u] < L[v]) update(L[v], R[v], 1, n, 1, x); else update(L[u], R[u], 1, n, 1, x); } } } return 0;}
树链剖分
#include <cstdio>#include <cstring>#include <vector>#include <algorithm>using namespace std;#define Del(a,b) memset(a,b,sizeof(a))const int N = 100005;int dep[N],siz[N],fa[N],id[N],son[N],val[N],top[N]; //top 最近的重链父节点int num,head[N],cnt;struct Edge{ int to,next;};Edge v[N*2];struct tree{ int x,y,val; void read(){ scanf("%d%d%d",&x,&y,&val); }};void add_Node(int x,int y){ v[cnt].to = y; v[cnt].next = head[x]; head[x] = cnt++;}tree e[N];void dfs1(int u, int f, int d) { dep[u] = d; siz[u] = 1; son[u] = 0; fa[u] = f; for(int i = head[u]; i != -1 ;i = v[i].next) { int to = v[i].to; if(to != f) { dfs1(to,u,d+1); siz[u] += siz[to]; if(siz[son[u]] < siz[to]) son[u] = to; } }}void dfs2(int u, int tp) { top[u] = tp; id[u] = ++num; if (son[u]) dfs2(son[u], tp); for(int i = head[u]; i != -1 ;i = v[i].next ) { int to = v[i].to; if(to == fa[u] || to == son[u]) continue; dfs2(to,to); }}#define lson(x) ((x<<1))#define rson(x) ((x<<1)+1)struct Tree{ int l,r,val;};Tree tree[4*N];void pushup(int x) { tree[x].val = tree[lson(x)].val + tree[rson(x)].val;}void build(int l,int r,int v){ tree[v].l=l; tree[v].r=r; if(l==r){ tree[v].val = val[l]; return ; } int mid=(l+r)>>1; build(l,mid,v*2); build(mid+1,r,v*2+1); pushup(v);}void update(int o,int v,int val) //log(n){ if(tree[o].l==tree[o].r) { tree[o].val = val; return ; } int mid = (tree[o].l+tree[o].r)/2; if(v<=mid) update(o*2,v,val); else update(o*2+1,v,val); pushup(o);}int query(int o,int l, int r){ if (tree[o].l >= l && tree[o].r <= r) { return tree[o].val; } int mid = (tree[o].l + tree[o].r) / 2; if(r<=mid) return query(o+o,l,r); else if(l>mid) return query(o+o+1,l,r); else return query(o+o,l,mid) + query(o+o+1,mid+1,r);}int Yougth(int u, int v) { int tp1 = top[u], tp2 = top[v]; int ans = 0; while (tp1 != tp2) { if (dep[tp1] < dep[tp2]) { swap(tp1, tp2); swap(u, v); } ans += query(1,id[tp1], id[u]); u = fa[tp1]; tp1 = top[u]; } if (u == v) return ans; if (dep[u] > dep[v]) swap(u, v); ans += query(1,id[son[u]], id[v]); return ans;}int main(){ int n,m,s; while(~scanf("%d%d%d",&n,&m,&s)) { cnt = 0; memset(head,-1,sizeof(head)); for(int i=1;i<n;i++) { e[i].read(); add_Node(e[i].x,e[i].y); add_Node(e[i].y,e[i].x); } num = 0; dfs1(1,0,1); dfs2(1,1); for(int i=1;i<n;i++) { if(dep[e[i].x] < dep[e[i].y]) swap(e[i].x,e[i].y); val[id[e[i].x]] = e[i].val; } build(1,num,1); for(int i=0;i<m;i++) { int ok,x,y; scanf("%d",&ok); if(ok==0) { scanf("%d",&x); printf("%d\n",Yougth(s,x)); s = x; } else { scanf("%d%d",&x,&y); update(1,id[e[x].x],y); } } } return 0;}
1 0
- POJ 2763 Housewife Wind
- POJ 2763 Housewife Wind
- poj 2763 Housewife Wind
- POJ 2763 Housewife Wind
- POJ 2763 Housewife Wind
- poj 2763 Housewife Wind
- POJ 2763 Housewife Wind
- POJ 2763 Housewife Wind
- POJ 2763 Housewife Wind
- poj 2763 Housewife Wind
- poj 2763 Housewife Wind(树链剖分)
- POJ 2763 Housewife Wind 树链剖分
- POJ 2763 Housewife Wind 树链剖分
- poj 2763 Housewife Wind(树链剖分)
- poj 2763 Housewife Wind 树链剖分
- POJ 2763 Housewife Wind (树链剖分)
- Housewife Wind - POJ 2763 树链刨分
- POJ 2763 Housewife Wind 树链剖分
- Character
- Mac OX上安装MongoDb
- 利用runtime 实现自定义Model归档
- android限制edittext最大行数的方法
- bzoj3561 DZY Loves Math VI 莫比乌斯函数
- POJ 2763 Housewife Wind
- 何时使用SpringAOP与aspectJ
- sql newid()随机函数
- intellij idea中文变口口
- iOS网络编程实践--NSStream实现TCP Socket iPhone客户端
- iOS9适配
- 不得不说的Volte的真相。
- vi/vim基本使用方法
- Android学习笔记day4