POJ3237 Tree (树链剖分)
作者:互联网
通过打懒标记实现区间取反,和线段树基本操作都差不多。
本题还是一道边权化为点权的问题。
200行巨长代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=10010; 6 int head[maxn],cnt=0,total=0;//头结点 7 int fa[maxn],dep[maxn];//父亲,深度 8 int size[maxn],son[maxn],top[maxn];//子树结点总数,重儿子,所在重链顶端结点 9 int id[maxn],rev[maxn];//u对应的dfs序下标,下标对于的u 10 int Max; 11 struct Edge{ 12 int u,v,w; 13 }a[maxn]; 14 15 struct edge{ 16 int to,next; 17 }e[maxn<<1]; 18 19 struct node{//结点 20 int l,r,Max,Min,lazy;//l,r区间左右端点,区间最值 ,懒标记 21 }tree[maxn<<2]; //树结点存储数组 22 23 void add(int u,int v){ 24 e[++cnt].to=v; 25 e[cnt].next=head[u]; 26 head[u]=cnt; 27 } 28 29 void init(){ 30 cnt=total=0; 31 memset(head,0,sizeof(head)); 32 memset(son,0,sizeof(son)); 33 } 34 35 void dfs1(int u,int f){//求dep,fa,size,son 36 size[u]=1; 37 for(int i=head[u];i;i=e[i].next){ 38 int v=e[i].to; 39 if(v==f)//父节点 40 continue; 41 dep[v]=dep[u]+1;//深度 42 fa[v]=u; 43 dfs1(v,u); 44 size[u]+=size[v]; 45 if(size[v]>size[son[u]]) 46 son[u]=v; 47 } 48 } 49 50 void dfs2(int u,int t){//求top,id 51 top[u]=t; 52 id[u]=++total;//u对应的dfs序下标 53 rev[total]=u;//dfs序下标对应的结点u 54 if(!son[u]) 55 return; 56 dfs2(son[u],t);//沿着重儿子dfs 57 for(int i=head[u];i;i=e[i].next){ 58 int v=e[i].to; 59 if(v!=fa[u]&&v!=son[u]) 60 dfs2(v,v); 61 } 62 } 63 64 void build(int i,int l,int r){//初始化线段树,i表示存储下标,区间[l,r] 65 tree[i].l=l; 66 tree[i].r=r; 67 tree[i].Max=tree[i].Min=tree[i].lazy=0; 68 if(l==r) return; 69 int mid=(l+r)/2;//划分点 70 build(i<<1,l,mid); 71 build((i<<1)|1,mid+1,r); 72 } 73 74 void push_up(int i){//上传 75 tree[i].Max=max(tree[i<<1].Max,tree[(i<<1)|1].Max); 76 tree[i].Min=min(tree[i<<1].Min,tree[(i<<1)|1].Min); 77 } 78 79 void push_down(int i){//下传 80 if(tree[i].l==tree[i].r) return; 81 if(tree[i].lazy){//下传给左右孩子,懒标记清零 82 tree[i<<1].Max=-tree[i<<1].Max; 83 tree[i<<1].Min=-tree[i<<1].Min; 84 swap(tree[i<<1].Min,tree[i<<1].Max); 85 tree[(i<<1)|1].Max=-tree[(i<<1)|1].Max; 86 tree[(i<<1)|1].Min=-tree[(i<<1)|1].Min; 87 swap(tree[(i<<1)|1].Max,tree[(i<<1)|1].Min); 88 tree[i<<1].lazy^=1; 89 tree[(i<<1)|1].lazy^=1; 90 tree[i].lazy=0; 91 } 92 } 93 94 void update(int i,int k,int val){//点更新,线段树的第k个值为val 95 if(tree[i].l==k&&tree[i].r==k){ 96 tree[i].Max=val; 97 tree[i].Min=val; 98 tree[i].lazy=0; 99 return; 100 } 101 push_down(i); 102 int mid=(tree[i].l+tree[i].r)/2; 103 if(k<=mid) update(i<<1,k,val); 104 else update((i<<1)|1,k,val); 105 push_up(i); 106 } 107 108 void update2(int i,int l,int r){//区间更新,线段树的区间[l,r]取反 109 if(tree[i].l>=l&&tree[i].r<=r){ 110 tree[i].Max=-tree[i].Max; 111 tree[i].Min=-tree[i].Min; 112 swap(tree[i].Max,tree[i].Min); 113 tree[i].lazy^=1; 114 return;//取反并打上标记 115 } 116 push_down(i);//下传标记 117 int mid=(tree[i].l+tree[i].r)/2; 118 if(l<=mid) update2(i<<1,l,r); 119 if(r>mid) update2((i<<1)|1,l,r); 120 push_up(i); 121 } 122 123 void query(int i,int l,int r){//查询线段树中[l,r]的最大值 124 if(tree[i].l>=l&&tree[i].r<=r){//找到该区间 125 Max=max(Max,tree[i].Max); 126 return; 127 } 128 push_down(i);//下传标记 129 int mid=(tree[i].l+tree[i].r)/2; 130 if(l<=mid) query(i<<1,l,r); 131 if(r>mid) query((i<<1)|1,l,r); 132 push_up(i); 133 } 134 135 void ask(int u,int v){//求u,v之间的最值 136 while(top[u]!=top[v]){//不在同一条重链上 137 if(dep[top[u]]<dep[top[v]]) 138 swap(u,v); 139 query(1,id[top[u]],id[u]);//u顶端结点和u之间 140 u=fa[top[u]]; 141 } 142 if(u==v) return; 143 if(dep[u]>dep[v])//在同一条重链上 144 swap(u,v); //深度小的结点为u 145 query(1,id[son[u]],id[v]);//注意是son[u] 146 } 147 148 void Negate(int u,int v){//把u-v路径上的边的值取相反数 149 while(top[u]!=top[v]){//不在同一条重链上 150 if(dep[top[u]]<dep[top[v]]) 151 swap(u,v); 152 update2(1,id[top[u]],id[u]);//u顶端结点和u之间 153 u=fa[top[u]]; 154 } 155 if(u==v) return; //不要忘了加上这一步 156 if(dep[u]>dep[v])//在同一条重链上 157 swap(u,v); //深度小的结点为u 158 update2(1,id[son[u]],id[v]);//注意是son[u] 159 } 160 161 int main(){ 162 int T,n; 163 scanf("%d",&T); 164 while(T--){ 165 init(); 166 scanf("%d",&n); 167 for(int i=1;i<n;i++){ 168 scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w); 169 add(a[i].u,a[i].v); 170 add(a[i].v,a[i].u); 171 } 172 dep[1]=1; 173 dfs1(1,0); 174 dfs2(1,1); 175 build(1,1,total);//创建线段树 176 for(int i=1;i<n;i++){//边权化为点权 177 if(dep[a[i].u]>dep[a[i].v]) 178 swap(a[i].u,a[i].v); 179 update(1,id[a[i].v],a[i].w); 180 } 181 char op[10]; 182 int u,v; 183 while(scanf("%s",op)==1){ 184 if(op[0]=='D')break; 185 scanf("%d%d",&u,&v); 186 if(op[0]=='Q'){ 187 Max=-0x3f3f3f3f; 188 ask(u,v);//查询u->v路径上边权的最大值 189 printf("%d\n",Max); 190 } 191 else if(op[0]=='C') 192 update(1,id[a[u].v],v);//改变第u条边的值为v 193 else Negate(u,v);//区间取反 194 } 195 } 196 return 0; 197 }
标签:剖分,int,tree,top,Tree,son,maxn,POJ3237,id 来源: https://www.cnblogs.com/yhxnoerror/p/16435869.html