test 10 problem C:最近公共祖先(线段树+乱搞)
2016-11-16 16:55
375 查看
题解:线段树+乱搞。
我们考虑将点x改为黑点的贡献,对于x子树中的点他们都可以取到x的值,利用dfs序,用线段树更新区间答案即可。对于x到根路径上的点,他们多了一个儿子有黑点,那除去这个儿子中点,其他的点都可以取到他的权值,所以也可以实现区间更新。当一个点有不少于2儿子同时拥有黑点的时候,他的整棵子树都可以拥有它的权值,直接整个子树更新即可,因这个点上面的点已经记录过当前这个儿子的贡献了,也就是对于他的父亲目前拥有的黑点属于同一个儿子,没有再更新的必要了,所以直接退出即可,否则向上跳,直到根为止。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 200003 using namespace std; int n,m,tot,sz,vis ; int tr[N*4],val ,dfsn ,pos ,belong ,l ,r ,delta[N*4],cover[N*4],delta1[N*4]; int point ,v ,next ,fa ,deep ,size ,son ,base ,sum ; void add(int x,int y) { tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; //cout<<x<<" "<<y<<endl; } void dfs(int x,int f) { deep[x]=deep[f]+1; size[x]=1; for (int i=point[x];i;i=next[i]) if (v[i]!=f) { sum[x]++; fa[v[i]]=x; dfs(v[i],x); size[x]+=size[v[i]]; if (size[son[x]]<size[v[i]]) son[x]=v[i]; } } void dfs1(int x,int chain) { belong[x]=chain; dfsn[++sz]=x; pos[x]=sz; l[x]=r[x]=sz; if (!son[x]) return ; dfs1(son[x],chain); for (int i=point[x];i;i=next[i]) if (v[i]!=son[x]&&v[i]!=fa[x]) dfs1(v[i],v[i]); r[x]=sz; } void pushdown(int now) { if (delta[now]!=-1) { tr[now<<1]=max(tr[now<<1],delta[now]); tr[now<<1|1]=max(tr[now<<1|1],delta[now]); delta[now<<1]=max(delta[now<<1],delta[now]); delta[now<<1|1]=max(delta[now<<1|1],delta[now]); delta[now]=-1; } } void qjchange(int now,int l,int r,int ll,int rr,int v) { if (ll>rr||!ll) return; if(ll<=l&&r<=rr) { tr[now]=max(tr[now],v); delta[now]=max(delta[now],v); return; } pushdown(now); int mid=(l+r)/2; if (ll<=mid) qjchange(now<<1,l,mid,ll,rr,v); if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,v); } int segpoint(int now,int l,int r,int x) { if (l==r) return tr[now]; pushdown(now); int mid=(l+r)/2; if (x<=mid) return segpoint(now<<1,l,mid,x); else return segpoint(now<<1|1,mid+1,r,x); } int main() { freopen("lca3.in","r",stdin); freopen("my.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&val[i]); for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); } dfs(1,0); dfs1(1,1); //for (int i=1;i<=n;i++) //cout<<fa[i]<<" "; //cout<<endl; memset(tr,-1,sizeof(tr)); memset(delta,-1,sizeof(delta)); for (int i=1;i<=m;i++) { char s[10]; int x; scanf("%s%d",s,&x); if (s[0]=='Q') printf("%d\n",segpoint(1,1,n,pos[x])); else { if (base[x]==1) { qjchange(1,1,n,l[x],r[x],val[x]); continue; } qjchange(1,1,n,l[x],r[x],val[x]); base[x]++; while (fa[x]){ int f=fa[x]; if (base[f]==1) { qjchange(1,1,n,l[f],r[f],val[f]); break; } qjchange(1,1,n,l[f],l[x]-1,val[f]); qjchange(1,1,n,r[x]+1,r[f],val[f]); base[f]++; x=fa[x]; } } } }
相关文章推荐
- 5-10 顺序存储的二叉树的最近的公共祖先问题 (25分)
- HihoCoder 1067 最近公共祖先(ST离线算法)
- 【原创】【LCA】求最近公共祖先的三种方法(一)倍增 ※【USACO MAR11银组】聚会地点
- 【树链剖分】【树状数组】【最近公共祖先】【块状树】bzoj3631 [JLOI2014]松鼠的新家
- 顺序存储的二叉树的最近的公共祖先问题
- 【HDU 2586 How far away ?】 邻接表+dfs+LCA(最近公共祖先问题)
- LCA最近公共祖先 hdu-2586
- HDU2586.How far away ?——最近公共祖先(离线Tarjan)
- PAT 5-3 顺序存储的二叉树的最近的公共祖先问题【二叉树】
- 树上两点的最近公共祖先-Tarjan_LCA离线算法
- Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)
- 最近公共祖先
- 给出一棵二叉树的根节点和其中两个不同的节点求出它们最近的公共祖先节点
- 最近公共祖先 【NOIP2016提高A组集训第14场11.12】
- HIHO #1069 : 最近公共祖先·三(RMQ+DFS LCA在线算法)
- 【数据结构】二叉树中任意两节点的最近公共祖先节点
- hdu 2586 最近公共祖先 LCA
- hdu 4547 CD 最近公共祖先lcm (dfs+rmq)
- hihoCoder#1062(最近公共祖先一)
- 最近公共祖先