【POJ3237】Tree(树链剖分)
来源:互联网 发布:婚纱店网络客服好做么 编辑:程序博客网 时间:2024/06/02 17:07
题目描述
传送门
题解
想了一节语文课。
树链剖分模板题。但是这个是要修改边权,比修改点权麻烦一点。
和修改点权一样,重儿子、父亲等东西都需要记录,不同的是需要再记录一下每个点到它重儿子的边的编号,以及每个点到它的父亲的边的编号。
这样的话,我们在查询和修改的时候,大部分和修改点权一样,不同的是:如果u和v不在一条链上,f1为u所在的链上最顶端的点,f2为v所在的链上最顶端的点(假设f1深度大于f2),如果我们修改点权的话只需要修改f1到u的即可,但是要修改边权的话需要修改f1的父亲边到u的父亲边,然后再将u跳到f1的父亲。如果到了最后u和v到了一条链上,那么我们需要把u的儿子边到v的父亲边修改(假设
v的深度大于u),而如果u=v的话应该直接退出。
上述的预处理都通过两个dfs处理出来。
线段树维护最大值的话很简单,只需要再维护一个最小值。如果到了取反的话就把最大值和最小值分别*(-1)再交换。
自己体会一下,实在不行画一棵树搞一搞,没思路的时候上语文课的时候想一想也许会有意想不到的效果。原则就是修改和查询的时候不重不漏不多。
代码
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int max_n=1e4+5;const int max_e=max_n*2;const int mininf=-2100000000;const int max_N=max_n*4;int T,n,x,y,z,N,u,t,ans;int tot,next[max_e],point[max_n],v[max_e],c[max_e];int size[max_n],h[max_n],father[max_n],son[max_n],top[max_n];int sonedge[max_n],faedge[max_n],num[max_e],val[max_e];int maxn[max_N],minn[max_N],delta[max_N];char s[10];inline void clear(){ memset(next,0,sizeof(next)); memset(point,0,sizeof(point)); memset(v,0,sizeof(v)); memset(c,0,sizeof(c)); memset(size,0,sizeof(size)); memset(h,0,sizeof(h)); memset(father,0,sizeof(father)); memset(son,0,sizeof(son)); memset(sonedge,0,sizeof(sonedge)); memset(faedge,0,sizeof(faedge)); memset(top,0,sizeof(top)); memset(num,0,sizeof(num)); memset(val,0,sizeof(val)); memset(maxn,0,sizeof(maxn)); memset(minn,0,sizeof(minn)); memset(delta,0,sizeof(delta)); tot=0; n=x=y=z=N=u=t=ans=0;}inline void add(int x,int y,int z){ ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z; ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x; c[tot]=z;}inline void dfs_1(int x,int fa,int dep){ size[x]=1; h[x]=dep; father[x]=fa; int maxson=0; for (int i=point[x];i;i=next[i]) if (v[i]!=fa){ faedge[v[i]]=i; dfs_1(v[i],x,dep+1); size[x]+=size[v[i]]; if (maxson<size[v[i]]){ maxson=size[v[i]]; son[x]=v[i]; sonedge[x]=i; } }}inline void dfs_2(int x,int fa){ if (son[fa]!=x) top[x]=x; else top[x]=top[fa]; for (int i=point[x];i;i=next[i]) if (v[i]==son[x]){ num[i]=++N; val[N]=c[i]; dfs_2(son[x],x); } for (int i=point[x];i;i=next[i]) if (v[i]!=fa&&v[i]!=son[x]){ num[i]=++N; val[N]=c[i]; dfs_2(v[i],x); }}inline void update(int now){ maxn[now]=max(maxn[now<<1],maxn[now<<1|1]); minn[now]=min(minn[now<<1],minn[now<<1|1]);}inline void pushdown(int now,int l,int r,int mid){ if (delta[now]%2){ swap(maxn[now<<1],minn[now<<1]); maxn[now<<1]*=-1; minn[now<<1]*=-1; delta[now<<1]++; swap(maxn[now<<1|1],minn[now<<1|1]); maxn[now<<1|1]*=-1; minn[now<<1|1]*=-1; delta[now<<1|1]++; } delta[now]=0;}inline void build(int now,int l,int r){ int mid=(l+r)>>1; if (l==r){ maxn[now]=val[l]; minn[now]=val[l]; return; } build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(now);}inline void point_change(int now,int l,int r,int x,int v){ int mid=(l+r)>>1; if (l==r){ maxn[now]=v; minn[now]=v; return; } pushdown(now,l,r,mid); if (x<=mid) point_change(now<<1,l,mid,x,v); else point_change(now<<1|1,mid+1,r,x,v); update(now);}inline void interval_change(int now,int l,int r,int lrange,int rrange){ int mid=(l+r)>>1; if (lrange<=l&&r<=rrange){ swap(maxn[now],minn[now]); maxn[now]*=-1; minn[now]*=-1; delta[now]++; return; } pushdown(now,l,r,mid); if (lrange<=mid) interval_change(now<<1,l,mid,lrange,rrange); if (mid+1<=rrange) interval_change(now<<1|1,mid+1,r,lrange,rrange); update(now);}inline int query(int now,int l,int r,int lrange,int rrange){ int mid=(l+r)>>1,ans=mininf; if (lrange<=l&&r<=rrange) return maxn[now]; pushdown(now,l,r,mid); if (lrange<=mid) ans=max(ans,query(now<<1,l,mid,lrange,rrange)); if (mid+1<=rrange) ans=max(ans,query(now<<1|1,mid+1,r,lrange,rrange)); return ans;}inline void NEGATE(int u,int t){ int f1=top[u],f2=top[t]; while (f1!=f2){ if (h[f1]<h[f2]){ swap(u,t); swap(f1,f2); } interval_change(1,1,N,num[faedge[f1]],num[faedge[u]]); u=father[f1]; f1=top[u]; } if (u==t) return; if (h[u]>h[t]) swap(u,t); interval_change(1,1,N,num[sonedge[u]],num[faedge[t]]);}inline int QUERY(int u,int t){ int ans=mininf; int f1=top[u],f2=top[t]; while (f1!=f2){ if (h[f1]<h[f2]){ swap(u,t); swap(f1,f2); } ans=max(ans,query(1,1,N,num[faedge[f1]],num[faedge[u]])); u=father[f1]; f1=top[u]; } if (u==t) return ans; if (h[u]>h[t]) swap(u,t); ans=max(ans,query(1,1,N,num[sonedge[u]],num[faedge[t]])); return ans;}int main(){ scanf("%d",&T); while (T--){ clear(); scanf("%d",&n); for (int i=1;i<n;++i){ scanf("%d%d%d",&x,&y,&z); add(x,y,z); } dfs_1(1,0,1); dfs_2(1,0); build(1,1,N); scanf("%s",s); while (strlen(s)>4){ scanf("%d%d",&u,&t); switch(s[0]){ case 'C':{ if (num[u*2-1]) x=num[u*2-1]; else x=num[u*2]; point_change(1,1,N,x,t); break; } case 'N':{ NEGATE(u,t); break; } case 'Q':{ ans=QUERY(u,t); printf("%d\n",ans); break; } } scanf("%s",s); } }}
总结
①线段树只要牵扯到区间修改,所有的操作之前都要pushdown,所有的修改操作之后都要update
1 0
- 【POJ3237】Tree(树链剖分)
- 【POJ3237】Tree 树链剖分
- poj3237 Tree 树链剖分
- poj3237 Tree [树链剖分]
- 【POJ3237】Tree-树链剖分
- POJ3237 Tree【树链剖分】
- poj3237 Tree(树链剖分)
- poj3237--Tree(树链剖分+线段树)
- 树链剖分+线段树 poj3237 Tree
- poj3237 Tree
- 【poj3237】 Tree
- poj3237 Tree
- POJ3237:Tree
- 【poj3237】Tree
- POJ3237 Tree
- poj3237 Tree
- poj3237 Tree
- poj3237 树链剖分
- Java泛型
- GSON基本使用
- Query in Java as in Mongo shell 【Jongo】
- String类为何不可变,为何final修饰
- Java 简单选择排序
- 【POJ3237】Tree(树链剖分)
- C语言编译链接流程以及重要特性在编译器中实现
- Android中如何实现后台执行定时任务
- Hive 源头获取 终点获取
- 串
- Eclipse设置注释模板
- Codeforces 533B 树上的dp(求最大偶数个节点的权重和)
- sublime text 3 配置说明
- C#线程间同步的几种实现方式