2016shenyang-1002-HDU5893-List wants to travel-树链剖分+线段树维护不同区间段个数

肯定先无脑树链剖分,然后线段树维护一段区间不同个数,再维护一个左右端点的费用。

线段树更新,pushDown,pushUp的时候要注意考虑链接位置的费用是否相同

还有就是树链剖分操作的时候,维护上一个更新的位置的费用。

总之就是出现区间合并,就考虑总数是否要减一

好想不好写

//场上根本写不完啊

  1 /*--------------------------------------------------------------------------------------*/
  2
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <cstring>
  6 #include <ctype.h>
  7 #include <cstdlib>
  8 #include <cstdio>
  9 #include <vector>
 10 #include <string>
 11 #include <queue>
 12 #include <stack>
 13 #include <cmath>
 14 #include <set>
 15 #include <map>
 16
 17 //debug function for a N*M array
 18 #define debug_map(N,M,G) printf("\n");for(int i=0;i<(N);i++) 19 {for(int j=0;j<(M);j++){ 20 printf("%d",G[i][j]);}printf("\n");}
 21 //debug function for int,float,double,etc.
 22 #define debug_var(X) cout<<#X"="<<X<<endl;
 23 #define LL long long
 24 const int INF = 0x3f3f3f3f;
 25 const LL LLINF = 0x3f3f3f3f3f3f3f3f;
 26 /*--------------------------------------------------------------------------------------*/
 27 using namespace std;
 28
 29 int N,M,T;
 30 const int maxn = 2e5+100;
 31
 32 struct Edge{
 33     int x,y,val;
 34 }e[maxn];
 35
 36 vector <int> G[maxn];
 37
 38 int val[maxn],dep[maxn],siz[maxn],top[maxn],id[maxn],son[maxn],fa[maxn];
 39 int topw;
 40
 41 void init()
 42 {
 43     for(int i=0;i<maxn;i++) G[i].clear();
 44     topw = 0;
 45 }
 46
 47 void dfs_1(int u,int f,int d)
 48 {
 49     fa[u] = f;
 50     son[u] = 0;
 51     siz[u] = 1;
 52     dep[u] = d;
 53     for(int i=0;i<G[u].size();i++) if(G[u][i] != f)
 54     {
 55         dfs_1(G[u][i],u,d+1);
 56         siz[u] += siz[G[u][i]];
 57         if(siz[son[u]] < siz[G[u][i] ])
 58         {
 59             son[u] = G[u][i];
 60         }
 61     }
 62 }
 63
 64 void dfs_2(int u,int tp)
 65 {
 66     top[u] = tp;
 67     id[u] = ++topw;
 68     if(son[u]) dfs_2(son[u],tp);
 69     for(int i=0;i<G[u].size();i++) if(G[u][i]!=fa[u] && G[u][i] != son[u] )
 70     {
 71         dfs_2(G[u][i],G[u][i]);
 72     }
 73 }
 74
 75 void debug()
 76 {
 77     for(int i=1;i<=N;i++)
 78     {
 79         printf("%d siz:%d son:%d dep:%d fa:%d ",i,siz[i],son[i],dep[i],fa[i]);
 80         printf("top:%d id:%d\n",top[i],id[i]);
 81     }
 82     return ;
 83 }
 84
 85 /*-----------------------------------*/
 86 #define lson(x) (x<<1)
 87 #define rson(x) (x<<1|1)
 88
 89 struct SegmentTree{
 90     int l,r;
 91     int lazy;
 92     int num,lcost,rcost;
 93 }segtree[4*maxn];
 94
 95 void pushUp(int x)
 96 {
 97     segtree[x].num = segtree[lson(x)].num + segtree[rson(x)].num - (segtree[lson(x)].rcost==segtree[rson(x)].lcost? 1 : 0);
 98     segtree[x].lcost = segtree[lson(x)].lcost;
 99     segtree[x].rcost = segtree[rson(x)].rcost;
100     //printf("x:%d [%d,%d] num:%d\n",x,segtree[x].l,segtree[x].r,segtree[x].num);
101     //printf("lcost:%d rcost:%d\n",segtree[x].lcost,segtree[x].rcost);
102     //printf("l->rcost:%d r->lcost:%d\n",segtree[lson(x)].rcost,segtree[rson(x)].lcost);
103 }
104
105 void pushDown(int x)
106 {
107     if(segtree[x].lazy != -1)
108     {
109         segtree[lson(x)].lcost = segtree[lson(x)].rcost = segtree[x].lazy;
110         segtree[rson(x)].lcost = segtree[rson(x)].rcost = segtree[x].lazy;
111         segtree[lson(x)].num = segtree[rson(x)].num = 1;
112         segtree[lson(x)].lazy = segtree[rson(x)].lazy = segtree[x].lazy;
113         segtree[x].lazy = -1;
114     }
115 }
116
117 void Build(int l,int r,int x)
118 {
119     segtree[x].l = l;
120     segtree[x].r = r;
121     segtree[x].lazy = -1;
122     if(l == r)
123     {
124         segtree[x].num = 1;
125         segtree[x].lcost = segtree[x].rcost = val[l];
126         return ;
127     }
128     int mid = (l+r)>>1;
129     Build(l,mid,lson(x));
130     Build(mid+1,r,rson(x));
131     pushUp(x);
132 }
133
134 void update(int x,int L,int R,int cost)
135 {
136     if(segtree[x].l >= L && segtree[x].r <= R)
137     {
138         segtree[x].lcost = segtree[x].rcost = cost;
139         segtree[x].num = 1;
140         segtree[x].lazy = cost;
141         return ;
142     }
143     pushDown(x);
144     int mid = (segtree[x].l + segtree[x].r) >> 1;
145     if(L <= mid) update(lson(x),L,R,cost);
146     if(R >  mid) update(rson(x),L,R,cost);
147     pushUp(x);
148     return ;
149 }
150
151 int query(int x,int L,int R)
152 {
153     if(segtree[x].l >= L && segtree[x].r <= R)
154     {
155         return segtree[x].num;
156     }
157     pushDown(x);
158     int mid = (segtree[x].l + segtree[x].r) >> 1;
159     int ans = 0;
160
161     if(R <= mid) ans = query(lson(x),L,R);
162     else if(L > mid) ans = query(rson(x),L,R);
163     else ans = query(lson(x),L,R) + query(rson(x),L,R) - (segtree[lson(x)].rcost==segtree[rson(x)].lcost ? 1 : 0) ;
164     pushUp(x);
165     return ans;
166 }
167
168 int query_edge(int x,int pos)
169 {
170     if(segtree[x].l == segtree[x].r)
171     {
172         return segtree[x].lcost;
173     }
174     pushDown(x);
175     int res = 0;
176     int mid = (segtree[x].l + segtree[x].r) >> 1;
177     if(pos <= mid) res =  query_edge(lson(x),pos);
178     else           res =  query_edge(rson(x),pos);
179     pushUp(x);
180     return res ;
181 }
182
183 int Find(int u,int v)
184 {
185     int ans = 0,fu = top[u],fv = top[v];
186     int last_u=-1 , last_v = -1;
187     int last_u_color,last_v_color;
188     //printf("%d->%d\n",u,v);
189
190     while(fu != fv)
191     {
192         if(dep[fu] < dep[fv])
193         {
194             swap(fu,fv);swap(u,v);
195             swap(last_u,last_v);
196             swap(last_u_color,last_v_color);
197         }
198
199         //printf("query:[%d,%d] %d->%d ",id[fu],id[u],u,fu);
200         //printf("%d\n",query(1,id[fu],id[u]));
201         ans += query(1,id[fu],id[u]);
202         if(last_u == -1)
203         {
204             last_u = fu;
205             last_u_color = query_edge(1,id[fu]);
206         }
207         else
208         {
209             if(last_u != -1 && fa[last_u] == u)
210             {
211                 //printf("u sub:%d\n",(last_u_color==query_edge(1,id[u]) ? 1 : 0));
212                 ans -= (last_u_color==query_edge(1,id[u]) ? 1 : 0);
213                 last_u = fu;
214                 last_u_color = query_edge(1,id[fu]);
215             }
216         }
217         u = fa[fu];
218         fu = top[u];
219     }
220     if(u == v)
221     {
222         if(last_u != -1 && last_v != -1 && last_u_color==last_v_color) ans -= 1;
223         return ans;
224     }
225     if(dep[u] < dep[v])
226     {
227         swap(u,v);
228         swap(last_u,last_v);
229         swap(last_u_color,last_v_color);
230     }
231     //printf("query:[%d,%d] %d->%d ",id[son[v]],id[u],u,son[v]);
232     ans += query(1,id[son[v] ],id[u]);
233     //printf("%d*\n",query(1,id[son[v]],id[u]));
234
235     //printf("last_u:%d last_v:%d\n",last_u,last_v);
236     if(last_u != -1 && fa[last_u] == u)
237     {
238         //printf("u sub:%d last_u_color:%d u_color:%d\n",(last_u_color==query_edge(1,id[u]) ? 1 : 0),last_u_color,query_edge(1,id[u]));
239         ans -= (last_u_color==query_edge(1,id[u]) ? 1 : 0);
240         last_u = fu;
241         last_u_color = query_edge(1,id[u]);
242     }
243
244     if(last_v != -1 && fa[last_v] == v)
245     {
246         //printf("v sub:%d last_v_color:%d son[v]_color:%d\n",(last_v_color==query_edge(1,id[son[v]]) ? 1 : 0),last_v_color,query_edge(1,id[son[v]] ));
247         ans -= (last_v_color==query_edge(1,id[son[v]]) ? 1 : 0);
248         last_v = fv;
249         last_v_color = query_edge(1,id[son[v]]);
250     }
251
252     return ans;
253 }
254
255 void Change(int u,int v,int cost)
256 {
257     int fu = top[u],fv = top[v];
258     //printf("%d->%d\n",u,v);
259     while(fu != fv)
260     {
261         if(dep[fu] < dep[fv])
262         {
263             swap(fu,fv);swap(u,v);
264         }
265         //printf("change:[%d,%d] %d->%d %d\n",id[fu],id[u],u,fu,cost);
266         update(1,id[fu],id[u],cost);
267         u = fa[fu];
268         fu = top[u];
269     }
270     if(u == v) return ;
271     if(dep[u] < dep[v]) swap(u,v);
272     //printf("change:[%d,%d] %d->%d %d\n",id[son[v]],id[u],u,son[u],cost);
273     update(1,id[son[v]],id[u],cost);
274     return ;
275 }
276
277 int main()
278 {
279     //freopen("input","r",stdin);
280     while(~scanf("%d%d",&N,&M))
281     {
282         init();
283         int u,v,w;
284         for(int i=1;i<N;i++)
285         {
286             scanf("%d%d%d",&u,&v,&w);
287             e[i].x = u;e[i].y = v;e[i].val = w;
288             G[u].push_back(v);
289             G[v].push_back(u);
290         }
291         topw = 0;
292         dfs_1(1,0,1);
293         dfs_2(1,1);
294         //debug();
295         for(int i=1;i<N;i++)
296         {
297             if(dep[e[i].x] < dep[e[i].y]) swap(e[i].x,e[i].y);
298             val[id[e[i].x]] = e[i].val;
299         }
300
301         Build(1,topw,1);
302         char op[20];
303         //printf("-----------------\n");
304         for(int i=0;i<M;i++)
305         {
306             scanf("%s",op);
307             if(op[0] == ‘Q‘)
308             {
309                 scanf("%d%d",&u,&v);
310                 printf("%d\n",Find(u,v));
311             }
312             else
313             {
314                 scanf("%d%d%d",&u,&v,&w);
315                 Change(u,v,w);
316             }
317             //puts("");
318         }
319     }
320 }
时间: 2024-10-24 11:58:31

2016shenyang-1002-HDU5893-List wants to travel-树链剖分+线段树维护不同区间段个数的相关文章

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条探险航

HDU4897 (树链剖分+线段树)

Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作2:将所有 有且仅有一个点在a->b的路径中 的边的颜色翻转. 操作3:询问a->b的路径中的黑色边数量. 解题分析 考虑操作1,只需正常的树链剖分+线段树维护即可.用线段树维护每条边,tag_1[i]表示该区间中的黑色边数量. 考虑操作2,一个节点相邻的边只可能为重链和轻链,且重链的数目小于等于