【POJ3237】Tree-树链剖分

来源:互联网 发布:骰子模拟器 mac版 编辑:程序博客网 时间:2024/06/10 08:37

题目大意:有一棵树,每条边有边权,有两种操作:1.修改某条边的边权。2.将某两个点之间路径上所有边的边权修改成它的相反数。3.询问某两个点之间路径上的所有边的边权的最大值。对于每个询问,给出正确的答案。

做法:一道比较难的树链剖分题,需要注意的是,在用线段树维护时,需要多维护一个区间最小值,因为在取反时,最大值和最小值会互换。

以下是本人代码:

#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>#define inf 999999999using namespace std;int t,n,tot,f[10010],siz[10010],dep[10010],pos[10010],p,a,b,c;int d[10010][3],first[10010],son[10010],top[10010],root;int qpos[10010];char op[10];struct edge{  int v,next;}e[20010];int seg[40010],m[40010],segp[40010]; //seg:区间最大值,m:区间最小值,segp:取反标记void readin(int a,int b,int c){  e[++tot].v=b;  e[tot].next=first[a];  first[a]=tot;}void dfs1(int now){  siz[now]=1;son[now]=0;  for(int i=first[now];i>0;i=e[i].next)    if (e[i].v!=f[now]){  dep[e[i].v]=dep[now]+1;  f[e[i].v]=now;  dfs1(e[i].v);  siz[now]+=siz[e[i].v];  if (siz[e[i].v]>siz[son[now]]) son[now]=e[i].v;}}void dfs2(int now,int chain){  pos[now]=++p;top[now]=chain;  if (son[now]) dfs2(son[now],chain);  for(int i=first[now];i>0;i=e[i].next)    if (e[i].v!=f[now]&&e[i].v!=son[now])  dfs2(e[i].v,e[i].v);}void pushdown(int no){  if (segp[no]==-1)  {    int t;t=seg[no<<1];seg[no<<1]=-m[no<<1];m[no<<1]=-t;t=seg[(no<<1)+1];seg[(no<<1)+1]=-m[(no<<1)+1];m[(no<<1)+1]=-t;segp[no]=1;segp[no<<1]=-segp[no<<1];segp[(no<<1)+1]=-segp[(no<<1)+1];  }}void pushup(int no){  seg[no]=max(seg[no<<1],seg[(no<<1)+1]);  m[no]=min(m[no<<1],m[(no<<1)+1]);}void buildtree(int no,int l,int r){  int mid=(l+r)>>1;  segp[no]=1;  if (l==r) {seg[no]=d[qpos[l]][2];m[no]=seg[no];return;}  buildtree(no<<1,l,mid);  buildtree((no<<1)+1,mid+1,r);  pushup(no);}void change(int no,int l,int r,int a,int c){  int mid=(l+r)>>1;  if (l==r) {seg[no]=c;m[no]=c;return;}  pushdown(no);  if (a<=mid) change(no<<1,l,mid,a,c);  else change((no<<1)+1,mid+1,r,a,c);  pushup(no);}int querymx(int no,int l,int r,int s,int t){  int mid=(l+r)>>1;  if (l>=s&&r<=t) return seg[no];  int mx=-inf;  pushdown(no);  if (s<=mid) mx=max(mx,querymx(no<<1,l,mid,s,t));  if (t>mid) mx=max(mx,querymx((no<<1)+1,mid+1,r,s,t));  pushup(no);  return mx;}void neg(int no,int l,int r,int s,int t){  int mid=(l+r)/2;  if (l>=s&&r<=t)  {    segp[no]=-segp[no];int tmp=seg[no];seg[no]=-m[no];m[no]=-tmp;return;  }  pushdown(no);  if (s<=mid) neg(no<<1,l,mid,s,t);  if (t>mid) neg((no<<1)+1,mid+1,r,s,t);  pushup(no);}int query(int a,int b){  int mx=-inf;  while(top[a]!=top[b])  {    if (dep[top[a]]<dep[top[b]]) swap(a,b);mx=max(mx,querymx(1,1,p,pos[top[a]],pos[a]));a=f[top[a]];  }  if (dep[a]<dep[b]) swap(a,b);  if (a!=b) mx=max(mx,querymx(1,1,p,pos[son[b]],pos[a]));  return mx;}void nega(int a,int b){  while(top[a]!=top[b])  {    if (dep[top[a]]<dep[top[b]]) swap(a,b);neg(1,1,p,pos[top[a]],pos[a]);a=f[top[a]];  }  if (dep[a]<dep[b]) swap(a,b);  if (a!=b) neg(1,1,p,pos[son[b]],pos[a]);}void read(){  op[0]=' ';  while (op[0]<'C'||op[0]>'Q') scanf("%s",op);}void input(){  scanf("%d",&n);  root=1;  memset(first,0,sizeof(first));  memset(seg,0,sizeof(seg));  memset(m,0,sizeof(m));  tot=f[root]=dep[root]=p=0;  for(int i=1;i<=n-1;i++)  {    scanf("%d %d %d",&a,&b,&c);d[i][0]=a;d[i][1]=b;d[i][2]=c;readin(a,b,c);readin(b,a,c);  }  dfs1(root);  dfs2(root,root);  for(int i=1;i<n;i++)  {if (dep[d[i][0]]>dep[d[i][1]]) swap(d[i][0],d[i][1]);qpos[pos[d[i][1]]]=i;  }  buildtree(1,1,p);}void work(){  int a,b;  for(read();op[0]!='D';read())  {    scanf("%d %d",&a,&b);    if (op[0]=='Q') printf("%d\n",query(a,b));else if (op[0]=='C') change(1,1,p,pos[d[a][1]],b);         else nega(a,b);  }}int main(){  for(scanf("%d",&t);t>0;t--)  {    input();work();  }    return 0;}


0 0
原创粉丝点击