BZOJ2157: 旅游 树链剖分 线段树

http://www.lydsy.com/JudgeOnline/problem.php?id=2157

在对树中数据进行改动的时候需要很多pushdown(具体操作见代码),不然会wa,大概原因和线段树区间修改需要很多pushup是一样的。

这个轻重链的方法特别好用,虽然第一次写树链剖分但是容易理解又有优秀复杂度的结构让人情不自禁orz。

(后来发现很久以前学lca的时候就学了树链剖分只不过忘了,mdzz)

因为忘了去掉测试代码的freopen,re了4次(虽然有三次就算不re也wa),发现一行一行检查对于数据结构的调试很有用(虽然一直找不出来re原因但是我起码避免了很多wa呀)。

代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 const int maxn=20100;
  8 const long long modn=1000000007;
  9 const int minf=1<<30;
 10 int n,m;char ch[5]={};
 11 struct nod{
 12     int y,next,v;
 13 }e[maxn*2];
 14 int head[maxn]={},tot=0;
 15 struct seg{
 16     int mi,mx,sum,c,l,r;
 17     int f,rev;
 18     seg(){mi=mx=sum=c=l=r=0;f=rev=0;}
 19 }t[maxn*4];
 20 int dep[maxn]={},crs[maxn]={},pos[maxn]={},road[maxn]={};
 21 int kid[maxn]={},fa[maxn]={},top[maxn]={};
 22 void init(int x,int y,int v){
 23     e[++tot].v=v;e[tot].y=y;
 24     e[tot].next=head[x];head[x]=tot;
 25 }
 26 int dfs1(int x,int pa){
 27     int y,siz=0,tsn=1,ma=0;
 28     fa[x]=pa;dep[x]=dep[pa]+1;
 29     for(int i=head[x];i;i=e[i].next){
 30         y=e[i].y;
 31         if(y==pa)continue;
 32         siz=dfs1(y,x);tsn+=siz;
 33         if(siz>ma)ma=siz,kid[x]=y;
 34         crs[(i+1)/2]=y;
 35     }
 36     return tsn;
 37 }
 38 void dfs2(int x,int pa){
 39     int y,v;
 40     pos[x]=++tot;top[x]=pa;
 41     if(kid[x])dfs2(kid[x],pa);
 42     for(int i=head[x];i;i=e[i].next){
 43         y=e[i].y;v=e[i].v;
 44         if(y==kid[x])road[pos[kid[x]]]=v;
 45         if(y==kid[x]||y==fa[x])continue;
 46         road[tot+1]=v;
 47         dfs2(y,y);
 48     }
 49 }
 50 void pushup(int x){
 51     int l=x*2,r=x*2+1;
 52     t[x].mx=max(t[l].mx,t[r].mx);
 53     t[x].mi=min(t[l].mi,t[r].mi);
 54     t[x].sum=t[l].sum+t[r].sum;
 55 }
 56 void pushdown(int x){
 57     if(t[x].f){
 58         int l=x*2,r=x*2+1;
 59         t[x].rev=t[x].f=0;
 60         t[x].mx=t[x].mi=t[x].c;
 61         t[x].sum=t[x].c*(t[x].r-t[x].l+1);
 62         if(t[x].l<t[x].r){
 63             t[l].c=t[r].c=t[x].c;
 64             t[l].f=t[r].f=1;
 65             t[l].rev=t[r].rev=0;
 66         }
 67         return;
 68     }
 69     if(t[x].rev){
 70         int l=x*2,r=x*2+1;
 71         t[x].rev=0;
 72         swap(t[x].mi,t[x].mx);
 73         t[x].mx*=-1;t[x].mi*=-1;t[x].sum*=-1;
 74         if(t[x].l<t[x].r){
 75             t[l].c*=-1;t[l].rev^=1;
 76             t[r].c*=-1;t[r].rev^=1;
 77         }
 78     }
 79 }
 80 void build(int x,int l,int r){
 81     t[x].l=l,t[x].r=r;
 82     if(l==r){
 83         t[x].mx=t[x].mi=t[x].sum=road[l];
 84         return;
 85     }
 86     int mid=(l+r)/2;
 87     build(x*2,l,mid);
 88     build(x*2+1,mid+1,r);
 89     pushup(x);
 90 }
 91 void cov(int x,int l,int r,int w){
 92     if(t[x].l>=l&&t[x].r<=r){
 93         t[x].f=1;t[x].c=w; pushdown(x);
 94         return;
 95     }
 96     pushdown(x);
 97     int mid=(t[x].l+t[x].r)/2;
 98     if(l<=mid)cov(x*2,l,r,w);
 99     pushdown(x*2);
100     if(r>mid) cov(x*2+1,l,r,w);
101     pushdown(x*2+1);
102     pushup(x);
103 }
104 void revs(int x,int l,int r){
105     if(t[x].l>=l&&t[x].r<=r){
106         t[x].c*=-1;t[x].rev^=1;
107         pushdown(x);
108         return;
109     }pushdown(x);
110     int mid=(t[x].l+t[x].r)/2;
111     if(l<=mid) revs(x*2,l,r);
112     pushdown(x*2);
113     if(r>mid) revs(x*2+1,l,r);
114     pushdown(x*2+1);
115     pushup(x);
116 }
117 int mi(int x,int l,int r){
118     pushdown(x);
119     if(t[x].l>=l&&t[x].r<=r){
120         return t[x].mi;
121     }
122     int mid=(t[x].l+t[x].r)/2,minn=minf;
123     if(l<=mid) minn=min(minn,mi(x*2,l,r));
124     if(r>mid) minn=min(minn,mi(x*2+1,l,r));
125     return minn;
126 }
127 int mx(int x,int l,int r){
128     pushdown(x);
129     if(t[x].l>=l&&t[x].r<=r){
130         return t[x].mx;
131     }
132     int mid=(t[x].l+t[x].r)/2,mxn=-minf;
133     if(l<=mid) mxn=max(mxn,mx(x*2,l,r));
134     if(r>mid) mxn=max(mxn,mx(x*2+1,l,r));
135     return mxn;
136 }
137 int su(int x,int l,int r){
138     pushdown(x);
139     if(t[x].l>=l&&t[x].r<=r){
140         return t[x].sum;
141     }
142     int mid=(t[x].l+t[x].r)/2,sumn=0;
143     if(l<=mid) sumn+=su(x*2,l,r);
144     if(r>mid) sumn+=su(x*2+1,l,r);
145     return sumn;
146 }
147 void mrev(int x,int y){
148     int a,b;
149     for(a=top[x],b=top[y];a!=b;){
150         if(dep[a]<dep[b])swap(a,b),swap(x,y);
151         revs(1,pos[a],pos[x]);
152         x=fa[a];a=top[x];
153     }
154     if(dep[x]>dep[y])swap(x,y);
155     if(x!=y) revs(1,pos[x]+1,pos[y]);
156 }
157 void doit(int x,int y,int k){
158     int a,b,mxn=-minf,minn=minf,sumn=0;
159     for(a=top[x],b=top[y];a!=b;){
160         if(dep[a]<dep[b])swap(a,b),swap(x,y);
161         if(k==0) sumn+=su(1,pos[a],pos[x]);
162         else if(k==1) mxn=max(mx(1,pos[a],pos[x]),mxn);
163         else minn=min(mi(1,pos[a],pos[x]),minn);
164         x=fa[a];a=top[x];
165     }
166     if(dep[x]>dep[y])swap(x,y);
167     if(x!=y){
168         if(k==0) sumn+=su(1,pos[x]+1,pos[y]);
169         else if(k==1) mxn=max(mx(1,pos[x]+1,pos[y]),mxn);
170         else minn=min(mi(1,pos[x]+1,pos[y]),minn);
171     }
172     if(k==0) printf("%d\n",sumn);
173     else if(k==1) printf("%d\n",mxn);
174     else printf("%d\n",minn);
175 }
176 int main(){
177     //freopen("wtf.in","r",stdin);
178     //freopen("wtf.out","w",stdout);
179     scanf("%d",&n);int x,y,z;
180     for(int i=1;i<n;i++){
181         scanf("%d%d%d",&x,&y,&z);
182         x++;y++;
183         init(x,y,z);init(y,x,z);
184     }tot=0;dfs1(1,1);dfs2(1,1);
185     build(1,1,n);
186     scanf("%d",&m);
187     for(int i=1;i<=m;i++){
188         scanf("%s%d%d",&ch,&x,&y);
189         if(ch[0]==‘N‘) mrev(x+1,y+1);
190         else if(ch[0]==‘C‘)cov(1,pos[crs[x]],pos[crs[x]],y);
191         else if(ch[1]==‘U‘)doit(x+1,y+1,0);
192         else if(ch[1]==‘A‘)doit(x+1,y+1,1);
193         else if(ch[1]==‘I‘)doit(x+1,y+1,2);
194     }
195     return 0;
196 }

时间: 2024-11-09 01:02:20

BZOJ2157: 旅游 树链剖分 线段树的相关文章

bzoj 2157: 旅游【树链剖分+线段树】

裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio> using namespace std; const int N=200005; int n,m,h[N],cnt,de[N],va[N],fa[N],si[N],hs[N],fr[N],id[N],tot,rl[N]; char c[10]; struct qwe { int ne,no,to,va

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

BZOJ2243 (树链剖分+线段树)

Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. 解题分析 树链剖分+线段树. 开一个记录类型,记录某一段区间的信息.l 表示区间最左侧的颜色 , r 表示区间最右侧的颜色 , sum 表示区间中颜色段数量. 合并时判断一下左区间的右端点和有区间的左端点的颜色是否一样. 树上合并时需要用两个变量ans1,ans2来存储.ans1表示x往上走时形成的链的信息,

bzoj4304 (树链剖分+线段树)

Problem T2 (bzoj4304 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 解题分析 练手题.树链剖分+线段树. 参考程序 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #incl

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并

题目描述 由乃正在做她的OJ.现在她在处理OJ上的用户排名问题.OJ上注册了n个用户,编号为1-",一开始他们按照编号 排名.由乃会按照心情对这些用户做以下四种操作,修改用户的排名和编号:然而由乃心情非常不好,因为Deus天 天问她题...因为Deus天天问由乃OI题,所以由乃去学习了一下OI,由于由乃智商挺高,所以OI学的特别熟练她 在RBOI2016中以第一名的成绩进入省队,参加了NOI2016获得了金牌保送 Deus:这个题怎么做呀? yuno:这个不是NOI2014的水题吗... Deu

HDU 2460 Network(双连通+树链剖分+线段树)

HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链剖分+线段树处理 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #pragma comment(linke

【bzoj1959】[Ahoi2005]LANE 航线规划 离线处理+树链剖分+线段树

题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1.2.3……. 一些先遣飞船已经出发,在星球之间开辟探险航线. 探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线. 例如下图所示: 在5个星球之间,有5条探险航