ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

POJ3237 Tree (树链剖分)

2022-07-01 20:34:52  阅读:128  来源: 互联网

标签:剖分 int tree top Tree son maxn POJ3237 id


通过打懒标记实现区间取反,和线段树基本操作都差不多。

本题还是一道边权化为点权的问题。

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有