[CodeVS4633][Mz]树链剖分练习

思路:

轻重链剖分+线段树。

  1 #include<cstdio>
  2 #include<vector>
  3 #include<cstring>
  4 const int N=100001;
  5 std::vector<int> e[N];
  6 inline void add_edge(const int u,const int v) {
  7     e[u].push_back(v);
  8     e[v].push_back(u);
  9 }
 10 int par[N]={0,1},dep[N]={0},size[N]={0};
 11 void dfs1(const int x) {
 12     size[x]=1;
 13     for(unsigned int i=0;i<e[x].size();i++) {
 14         if(e[x][i]==par[x]) continue;
 15         par[e[x][i]]=x,dep[e[x][i]]=dep[x]+1;
 16         dfs1(e[x][i]);
 17         size[x]+=size[e[x][i]];
 18     }
 19 }
 20 int top[N]={0},dfn[N],sz=0;
 21 void dfs2(const int x) {
 22     if(!top[x]) top[x]=x;
 23     dfn[x]=++sz;
 24     if(e[x].size()==1&&x!=1) return;
 25     int v=0;
 26     for(unsigned int i=0;i<e[x].size();i++) {
 27         if(e[x][i]==par[x]) continue;
 28         if(size[e[x][i]]>size[v]) v=e[x][i];
 29     }
 30     top[v]=top[x];
 31     dfs2(v);
 32     for(unsigned int i=0;i<e[x].size();i++) {
 33         if(e[x][i]==par[x]||e[x][i]==v) continue;
 34         dfs2(e[x][i]);
 35     }
 36 }
 37 class SegmentTree {
 38     #define _left <<1
 39     #define _right <<1|1
 40     private:
 41         int val[N<<2],tag[N<<2];
 42         int len(const int l,const int r) {
 43             return r-l+1;
 44         }
 45         void push_down(const int p,const int b,const int e) {
 46             if(!tag[p]) return;
 47             int mid=(b+e)>>1;
 48             tag[p _left]+=tag[p];
 49             tag[p _right]+=tag[p];
 50             val[p _left]+=tag[p]*len(b,mid);
 51             val[p _right]+=tag[p]*len(mid+1,e);
 52             tag[p]=0;
 53         }
 54         void push_up(const int p) {
 55             val[p]=val[p _left]+val[p _right];
 56         }
 57     public:
 58         SegmentTree() {
 59             memset(val,0,sizeof val);
 60             memset(tag,0,sizeof tag);
 61         }
 62         void modify(const int p,const int b,const int e,const int l,const int r) {
 63             if((b==l)&&(e==r)) {
 64                 val[p]+=len(b,e);
 65                 tag[p]++;
 66                 return;
 67             }
 68             push_down(p,b,e);
 69             int mid=(b+e)>>1;
 70             if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r));
 71             if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r);
 72             push_up(p);
 73         }
 74         int query(const int p,const int b,const int e,const int l,const int r) {
 75             if((b==l)&&(e==r)) return val[p];
 76             push_down(p,b,e);
 77             int mid=(b+e)>>1,ans=0;
 78             if(l<=mid) ans+=query(p _left,b,mid,l,std::min(mid,r));
 79             if(r>mid) ans+=query(p _right,mid+1,e,std::max(mid+1,l),r);
 80             return ans;
 81         }
 82 };
 83 SegmentTree t;
 84 inline void swap(int &x,int &y) {
 85     int t;
 86     t=x;
 87     x=y;
 88     y=t;
 89 }
 90 int n;
 91 void modify(int x,int y) {
 92     for(;top[x]!=top[y];x=par[top[x]]) {
 93         if(dep[top[x]]<dep[top[y]]) swap(x,y);
 94         t.modify(1,1,n,dfn[top[x]],dfn[x]);
 95     }
 96     if(dep[x]<dep[y]) swap(x,y);
 97     t.modify(1,1,n,dfn[y],dfn[x]);
 98 }
 99 int query(int x,int y) {
100     int ans=0;
101     for(;top[x]!=top[y];x=par[top[x]]) {
102         if(dep[top[x]]<dep[top[y]]) swap(x,y);
103         ans+=t.query(1,1,n,dfn[top[x]],dfn[x]);
104     }
105     if(dep[x]<dep[y]) swap(x,y);
106     ans+=t.query(1,1,n,dfn[y],dfn[x]);
107     return ans;
108 }
109 int main() {
110     scanf("%d",&n);
111     for(int i=1;i<n;i++) {
112         int x,y;
113         scanf("%d%d",&x,&y);
114         add_edge(x,y);
115     }
116     dfs1(1);
117     dfs2(1);
118     int q;
119     scanf("%d",&q);
120     while(q--) {
121         int op,x,y;
122         scanf("%d%d%d",&op,&x,&y);
123         if(op==1) modify(x,y);
124         if(op==2) printf("%d\n",query(x,y));
125     }
126     return 0;
127 }
时间: 2024-12-19 00:42:51

[CodeVS4633][Mz]树链剖分练习的相关文章

codevs 4633 [Mz]树链剖分练习

时间限制: 1 s 空间限制: 64000 KB 题目等级 : 大师 Master 题目描述 Description 给定一棵结点数为n的树,初始点权均为0,有依次q个操作,每次操作有三个参数a,b,c,当a=1时,表示给b号结点到c号结点路径上的所有点(包括b,c,下同)权值都增加1,当a=2时,表示询问b号结点到c号结点路径上的所有点权值之和. 输入描述 Input Description 第一行,一个正整数n. 接下来n-1行,每行一对正整数x,y,表示x号结点和y号结点之间有一条边. 第

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

bzoj3694: 最短路(树链剖分/并查集)

bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿 这题可以用树链剖分或并查集写.树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用... 首先对于不在最短路径树上的边x->y,设t为最短路径树上lca(x,y),则t到y上的路径上的点i到根的距离都可以用h[x]+dis[x][y]+h[y]-h[i](h[]为深度)来更新,因为h[i]一定,只要让h[x]+dis[x][y]+h[y]最小就行,这里用树剖直接修改整条链上的数,就可以过了. 并查集的

洛谷 P3384 【模板】树链剖分

题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数N.M.R.P,分别表示树的结点个数.操作个数

bzoj1036 树的统计(树链剖分+线段树)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 15120  Solved: 6141[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

SPOJ QTREE Query on a tree ——树链剖分 线段树

[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 20005 int T,n,fr[maxn],h[maxn],to[maxn],ne[maxn]

树链剖分简(单)介(绍)

树链剖分可以算是一种数据结构(一大堆数组,按照这个意思,主席树就是一大堆线段树).将一棵树分割成许多条连续的树链,方便完成一下问题: 单点修改(dfs序可以完成) 求LCA(各种乱搞也可以) 树链修改(修改任意树上两点之间的唯一路径) 树链查询 (各种操作)  前两个内容可以用其他方式解决,但是下面两种操作倍增.st表,dfs序就很难解决(解决当然可以解决,只是耗时长点而已).下面开始步入正题. 树链剖分的主要目的是分割树,使它成一条链,然后交给其他数据结构(如线段树,Splay)来进行维护.常

bzoj1146整体二分+树链剖分+树状数组

其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 inline int read() 7 { 8 int x=0,f=1,ch=getchar(); 9 while(ch<