[POJ3237]树的维护
Posted 蒟蒻ZJO :-)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[POJ3237]树的维护相关的知识,希望对你有一定的参考价值。
P1424 - [POJ3237]树的维护
Description
给你由N个结点组成的树。树的节点被编号为1到N,边被编号为1到N-1。每一条边有一个权值。然后你要在树上执行一系列指令。指令可以是如下三种之一:
CHANGE i v:将第i条边的权值改成v。
NEGATE a b:将点a到点b路径上所有边的权值变成其相反数。
QUERY a b:找出点a到点b路径上各边的最大权值。
Input
第一行有一个整数N(N<=10000)。
接下来N-1行每行有三个整数a,b,c,代表点a和点b之间有一条权值为c的边。这些边按照其编号从小到大给出。
接下来是若干条指令(不超过10^5条),都按照上面所说的格式。
最后一行是"DONE".
Output
对每个“QUERY”指令,输出一行,即路径上各边的最大权值。
Sample Input
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
Sample Output
1
3
树链剖分,在线段树中维护一个区间最大和区间最小,
在进行取反操作时,将区间最小的相反数赋给最大,将区间最大值的相反数赋给最小,并标记lazy数组。
另外,根节点在线段树中的值为0,但这不需要管,因为不会查询到根节点。
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<ctime> 6 #include<cmath> 7 #include<string> 8 #include<vector> 9 #include<cstdio> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 #define maxn 10010 15 #define ls o*2 16 #define rs o*2+1 17 #define mi int mid=(l+r)>>1 18 using namespace std; 19 struct data{ 20 int nex,to,w; 21 }e[maxn*2]; 22 char s[10]; 23 int head[maxn],edge=0,n; 24 int top[maxn],dis[maxn],dad[maxn],son[maxn],size[maxn],dfn[maxn],dfp[maxn],deep[maxn]; 25 int b[maxn*4],b1[maxn*4],lazy[maxn*4]; 26 void dfs1(int x,int fa){ 27 size[x]++; 28 for(int i=head[x];i;i=e[i].nex){ 29 int u=e[i].to; 30 if(u==fa) continue; 31 dad[u]=x; 32 dis[u]=e[i].w; 33 deep[u]=deep[x]+1; 34 dfs1(u,x); 35 size[x]+=size[u]; 36 if(size[u]>size[son[x]]) son[x]=u; 37 } 38 } 39 int de=0; 40 void dfs2(int x,int fa){ 41 ++de; 42 dfn[x]=de;dfp[de]=x; 43 if(son[x]!=0) top[son[x]]=top[x],dfs2(son[x],x); 44 for(int i=head[x];i;i=e[i].nex){ 45 int v=e[i].to; 46 if(v==fa || v==son[x]) continue; 47 top[v]=v; 48 dfs2(v,x); 49 } 50 } 51 void add(int from,int to,int w){ 52 e[++edge].nex=head[from]; 53 e[edge].to=to; 54 e[edge].w=w; 55 head[from]=edge; 56 } 57 void build(int o,int l,int r){ 58 if(l==r){b[o]=dis[dfp[l]];b1[o]=dis[dfp[l]];return;} 59 mi; 60 build(ls,l,mid);build(rs,mid+1,r); 61 b[o]=min(b[ls],b[rs]); 62 b1[o]=max(b1[ls],b1[rs]); 63 } 64 void down(int o){ 65 if(lazy[o]==-1){ 66 int tmp=b[ls]; 67 b[ls]=-b1[ls];b1[ls]=-tmp; 68 } 69 if(lazy[o]==-1){ 70 int tmp=b[rs]; 71 b[rs]=-b1[rs];b1[rs]=-tmp; 72 } 73 lazy[ls]*=lazy[o],lazy[rs]*=lazy[o]; 74 lazy[o]=1; 75 } 76 int query(int o,int l,int r,int u,int v){ 77 if(l!=r)down(o); 78 if(l>=u && r<=v) return b1[o]; 79 if(l>v || r<u) return -1999999999; 80 mi; 81 if(v<=mid) return query(ls,l,mid,u,v); 82 else if(u>mid) return query(rs,mid+1,r,u,v); 83 else return max(query(ls,l,mid,u,mid),query(rs,mid+1,r,mid+1,v)); 84 } 85 int lca(int x,int y){ 86 int ans=-1999999999; 87 while(top[x]!=top[y]){ 88 if(deep[top[x]]>deep[top[y]]) ans=max(ans,query(1,1,n,dfn[top[x]],dfn[x])),x=dad[top[x]]; 89 else ans=max(ans,query(1,1,n,dfn[top[y]],dfn[y])),y=dad[top[y]]; 90 } 91 if(deep[x]>deep[y]) swap(x,y); 92 if(x!=y) 93 ans=max(ans,query(1,1,n,dfn[x]+1,dfn[y])); 94 return ans; 95 } 96 void negatee(int o,int l,int r,int u,int v){ 97 if(l!=r)down(o); 98 if(l>=u && r<=v){ 99 int tmp=b[o]; 100 b[o]=-b1[o];b1[o]=-tmp; 101 lazy[o]*=-1; 102 return; 103 } 104 mi; 105 if(v<=mid) negatee(ls,l,mid,u,v); 106 else if(u>mid) negatee(rs,mid+1,r,u,v); 107 else negatee(ls,l,mid,u,mid),negatee(rs,mid+1,r,mid+1,v); 108 b[o]=min(b[ls],b[rs]); 109 b1[o]=max(b1[ls],b1[rs]); 110 } 111 void lca1(int x,int y){ 112 while(top[x]!=top[y]){ 113 if(deep[top[x]]>deep[top[y]]) negatee(1,1,n,dfn[top[x]],dfn[x]),x=dad[top[x]]; 114 else negatee(1,1,n,dfn[top[y]],dfn[y]),y=dad[top[y]]; 115 } 116 if(deep[x]>deep[y]) swap(x,y); 117 if(x!=y) 118 negatee(1,1,n,dfn[x]+1,dfn[y]); 119 } 120 void change(int o,int l,int r,int k,int p){ 121 if(l!=r) down(o); 122 if(l==r){b[o]=p,b1[o]=p;return;} 123 mi; 124 if(k<=mid)change(ls,l,mid,k,p); 125 else change(rs,mid+1,r,k,p); 126 b[o]=min(b[ls],b[rs]); 127 b1[o]=max(b1[ls],b1[rs]); 128 } 129 int main() 130 { 131 freopen("!.in","r",stdin); 132 freopen("!.out","w",stdout); 133 scanf("%d",&n);int x,y,z; 134 for(int i=1;i<=4*n;i++) lazy[i]=1; 135 for(int i=1;i<n;i++) 136 scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z); 137 top[1]=1,dad[1]=1; 138 dfs1(1,0);dfs2(1,0);build(1,1,n); 139 while(1){ 140 scanf("%s",s); 141 if(s[0]==‘D‘) break; 142 if(s[0]==‘Q‘){ 143 int x,y; 144 scanf("%d%d",&x,&y); 145 printf("%d\n",lca(x,y)); 146 } 147 if(s[0]==‘C‘){ 148 int x,y;scanf("%d%d",&x,&y); 149 int k1=e[2*x-1].to,k2=e[2*x].to; 150 int k; 151 if(deep[k1]>deep[k2]) k=k1; 152 else k=k2; 153 change(1,1,n,dfn[k],y); 154 } 155 if(s[0]==‘N‘){ 156 int x,y; 157 scanf("%d%d",&x,&y); 158 lca1(x,y); 159 } 160 } 161 return 0; 162 }
以上是关于[POJ3237]树的维护的主要内容,如果未能解决你的问题,请参考以下文章
cogs 1583. [POJ 3237] 树的维护 树链剖分套线段树
POJ 3237 /// 树链剖分 线段树区间修改(*-1)