hdu 6162 Ch’s gift(树链剖分+主席树)

题目链接:hdu 6162 Ch’s gift

题意:

给你一棵树,树上每个点有一个权值,现在有m个询问,每次询问给你一个s,t,L,R,问你从s到t的路径上,权值在[L,R]内的总和为多少。

题解:

我感觉我写复杂了,用树链剖分来维护路径,然后用主席树来建立权值线段树乱搞。

 1 #include<bits/stdc++.h>
 2 #define mst(a,b) memset(a,b,sizeof(a))
 3 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 4 typedef long long ll;
 5 using namespace std;
 6
 7 const int N=1e5+7;
 8 int dep[N],sz[N],hs[N],top[N],tid[N],fid[N],fa[N],idx;
 9 int n,m,pp,x,y,a[N],g[N],nxt[2*N],v[2*N],ed;
10 int hsh[N*4],h_ed,root[N];
11
12 struct Node{int l,r;ll sum;}T[N*40];
13 int cnt;
14 ll ans;
15 struct Q{int s,t,a,b;}q[N];
16
17 int gid(int x){return lower_bound(hsh+1,hsh+1+h_ed,x)-hsh;}
18
19 void add(int &x,int y,int idx,int val,int l=1,int r=h_ed)
20 {
21     T[x=++cnt]=T[y],T[x].sum+=val;
22     if(l==r)return;
23     int mid=l+r>>1;
24     if(idx<=mid)add(T[x].l,T[y].l,idx,val,l,mid);
25     else add(T[x].r,T[y].r,idx,val,mid+1,r);
26 }
27
28 ll ask(int x,int y,int L,int R,int l=1,int r=h_ed)
29 {
30     if(L<=l&&r<=R)return T[y].sum-T[x].sum;
31     int mid=l+r>>1;ll an=0;
32     if(L<=mid)an+=ask(T[x].l,T[y].l,L,R,l,mid);
33     if(R>mid)an+=ask(T[x].r,T[y].r,L,R,mid+1,r);
34     return an;
35 }
36
37 inline void adg(int x,int y){v[++ed]=y,nxt[ed]=g[x],g[x]=ed;}
38
39 void dfs1(int u,int pre){
40     dep[u]=dep[pre]+1,hs[u]=0,fa[u]=pre,sz[u]=1;
41     for(int i=g[u];i;i=nxt[i])if(v[i]!=pre)
42     dfs1(v[i],u),sz[u]+=sz[v[i]],hs[u]=(sz[v[i]]>sz[hs[u]])?v[i]:hs[u];
43 }
44 void dfs2(int u,int tp){
45     top[u]=tp,tid[u]=++idx,fid[idx]=u;
46     if(hs[u])dfs2(hs[u],tp);
47     for(int i=g[u];i;i=nxt[i])
48     if(v[i]!=fa[u]&&v[i]!=hs[u])dfs2(v[i],v[i]);
49 }
50
51 void up(int x,int y,int a,int b){
52     int fx=top[x],fy=top[y];
53     while(fx!=fy){
54         if(dep[fx]>dep[fy])
55         {
56             int xx=tid[fx],yy=tid[x];
57             if(xx>yy)swap(xx,yy);
58             ans+=ask(root[xx-1],root[yy],a,b);
59             x=fa[fx],fx=top[x];
60         }
61         else {
62             int xx=tid[fy],yy=tid[y];
63             if(xx>yy)swap(xx,yy);
64             ans+=ask(root[xx-1],root[yy],a,b);
65             y=fa[fy],fy=top[y];
66         }
67     }
68     if(dep[x]>dep[y])x^=y,y^=x,x^=y;
69     int xx=tid[x],yy=tid[y];
70     if(xx>yy)swap(xx,yy);
71     ans+=ask(root[xx-1],root[yy],a,b);
72 }
73
74 int main(){
75     while(~scanf("%d%d",&n,&m)){
76         F(i,1,n)scanf("%d",a+i),hsh[i]=a[i];
77         cnt=0,ed=0,h_ed=n;F(i,1,n)g[i]=0;
78         F(i,2,n)scanf("%d%d",&x,&y),adg(x,y),adg(y,x);
79         F(i,1,m)
80         {
81             scanf("%d%d%d%d",&q[i].s,&q[i].t,&q[i].a,&q[i].b);
82             hsh[++h_ed]=q[i].a,hsh[++h_ed]=q[i].b;
83         }
84         sort(hsh+1,hsh+1+h_ed),h_ed=unique(hsh+1,hsh+1+h_ed)-hsh-1;
85         dfs1(1,0),idx=0,dfs2(1,1);
86         F(i,1,idx)add(root[i],root[i-1],gid(a[fid[i]]),a[fid[i]]);
87         F(i,1,m){
88             int S=q[i].s,T=q[i].t,a=q[i].a,b=q[i].b;
89             ans=0,up(S,T,gid(a),gid(b));
90             printf("%lld%c",ans," \n"[i==m]);
91         }
92     }
93     return 0;
94 }

时间: 2024-10-26 05:52:39

hdu 6162 Ch’s gift(树链剖分+主席树)的相关文章

BZOJ3531 SDOI2014 旅行 - 树链剖分,主席树

题意:给定一棵树,树上每个点有权值和类型.支持:修改某个点的类型:修改某个点的权值:询问某条链上某个类型的点的和/最大值.点数/类型数/询问数<=100000. 分析: 树链剖分,对每个类型的点建立线段树(动态开点). note: 忘记写t_query返回值调半天-- 莫名其妙地1A 代码: 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int a[5000005],s[5000005],dep[100005],size[10

BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链上的第k大值 题解 水题. 就是烦了一点. 树链剖分+带修主席树. 带修主席树: BZOJ1901 Zju2112 Dynamic Rankings 主席树 代码 #include <cstring> #include <cstdio> #include <algorithm&g

[BZOJ 4012][HNOI2015]开店(树链剖分+主席树)

Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面向什么样的人群.很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n个地方,编号为 1 到 n,被 n-1 条带权的边连接起来.每个地方都住着一个妖怪,其中第 i 个地方的妖怪年龄是 x_i.妖怪都是些比较喜欢安静的家伙,所以它们并不希望和很多妖怪相邻.所以这

bzoj2588 -- 树链剖分+主席树

先将权值离散. 显然可以对于每个结点建一棵权值线段树存这个点到根结点的路径上的点权,询问时在线段树上二分,但这样时间是O(n2log2n)的. 然后想到用主席树优化,时间复杂度O(n*log2n). 代码: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace st

Codechef FIBTREE 树链剖分 主席树 LCA 二次剩余 快速幂

原文链接https://www.cnblogs.com/zhouzhendong/p/CC-FIBTREE.html 题目传送门 - CC-FIBTREE 题意 题解 代码 #include <bits/stdc++.h> using namespace std; typedef long long LL; const int N=100005,S=N*200,mod=1e9+9; struct Gragh{ static const int M=N*2; int cnt,y[M],nxt[M

2019年ICPC南昌网络赛 J. Distance on the tree 树链剖分+主席树

边权转点权,每次遍历到下一个点,把走个这条边的权值加入主席树中即可. #include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> using namespace std; const int maxx = 2e5+10; struct node{ int l,r,cnt; }tree[maxx*40]; int head[maxx],rk[maxx],siz[maxx

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

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

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

HDU 3966 Aragorn&#39;s Story (树链剖分+线段树)

题意:给你一棵树,然后有三种操作 I L R K: 把L与R的路径上的所有点权值加上K D L R K:把L与R的路径上的所有点权值减去K Q X:查询节点编号为X的权值 思路:树链剖分裸题(我还没有怎么学懂,但基本已经没有什么太大的问题,主要的问题就在于点或者边对于数据结构的映射关系是,主要没有单独手写过树链剖分,所以对这部分 没有什么体会) 我们知道树链剖分是一种将树剖为链的一种算法,其思想和dfs序差不多,但根据树链剖分的性质,我们的重链是连续的区间,这样对于重链或者重链上的点我们可以方便