题意:一棵树,每个点有个权值,m次询问,每次给你一条链和两个值a,b,问你这条链上权值在[a,b]之间的权值的和是多少。
std竟然是2个log的……完全没必要链剖,每个结点的主席树从其父节点转移过来,这样每个结点的主席树存储的就是它到根点的权值。
然后链询问,直接在主席树上作差,T[u]+T[v]-T[lca(u,v)]-T[fa(lca(u,v))]即可。只有一个log。
当然要先离散化。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 300005
typedef long long ll;
int v[N<<1],first[N],nex[N<<1],en;
void AddEdge(int U,int V)
{
v[++en]=V;
nex[en]=first[U];
first[U]=en;
}
struct Point{int v,p;}t[N];
bool operator < (Point a,Point b){return a.v<b.v;}
int n,m,ma[N],a[N],zy;
struct Node{ll v;int lc,rc;}T[100005*27];
int root[N],e=1;
void BuildTree(int cur,int l,int r)
{
if(l==r) return;
int m=(l+r>>1);
T[cur].lc=++e;
BuildTree(T[cur].lc,l,m);
T[cur].rc=++e;
BuildTree(T[cur].rc,m+1,r);
}
void Insert(int pre,int cur,int p,int v,int l,int r)
{
if(l==r)
{
T[cur].v=T[pre].v+(ll)v;
return;
}
int m=(l+r>>1);
if(p<=m)
{
T[cur].lc=++e;
T[cur].rc=T[pre].rc;
Insert(T[pre].lc,T[cur].lc,p,v,l,m);
}
else
{
T[cur].rc=++e;
T[cur].lc=T[pre].lc;
Insert(T[pre].rc,T[cur].rc,p,v,m+1,r);
}
T[cur].v=T[T[cur].lc].v+T[T[cur].rc].v;
}
int top[N],siz[N],son[N],fa[N],dep[N];
void df1(int U)
{
siz[U]=1;
for(int i=first[U];i;i=nex[i])
if(v[i]!=fa[U])
{
fa[v[i]]=U;
dep[v[i]]=dep[U]+1;
df1(v[i]);
siz[U]+=siz[v[i]];
if(siz[v[i]]>siz[son[U]])
son[U]=v[i];
}
}
void df2(int U)
{
if(son[U])
{
top[son[U]]=top[U];
df2(son[U]);
}
for(int i=first[U];i;i=nex[i])
if(v[i]!=fa[U]&&v[i]!=son[U])
{
top[v[i]]=v[i];
df2(v[i]);
}
}
int lca(int U,int V)
{
while(top[U]!=top[V])
{
if(dep[top[U]]<dep[top[V]])
swap(U,V);
U=fa[top[U]];
}
if(dep[U]>dep[V])
swap(U,V);
return U;
}
void dfs(int U)
{
root[U]=++e;
Insert(root[fa[U]],root[U],a[U],ma[a[U]],1,zy);
for(int i=first[U];i;i=nex[i])
if(v[i]!=fa[U])
dfs(v[i]);
}
ll query(int ql,int qr,int LCA,int FLCA,int A,int B,int l,int r)
{
if(A<=l && r<=B){
return T[ql].v+T[qr].v-T[LCA].v-T[FLCA].v;
}
int m=(l+r>>1);
ll res=0;
if(A<=m)
res+=query(T[ql].lc,T[qr].lc,T[LCA].lc,T[FLCA].lc,A,B,l,m);
if(m<B)
res+=query(T[ql].rc,T[qr].rc,T[LCA].rc,T[FLCA].rc,A,B,m+1,r);
return res;
}
int xs[N],ys[N],as[N],bs[N];
int main()
{
//freopen("b.in","r",stdin);
//freopen("b.out","w",stdout);
int X,Y,W;
while(scanf("%d%d",&n,&m)!=EOF){
e=0;
zy=0;
en=0;
memset(first,0,sizeof(first));
memset(a,0,sizeof(a));
memset(ma,0,sizeof(ma));
memset(t,0,sizeof(t));
memset(T,0,sizeof(T));
memset(root,0,sizeof(root));
memset(top,0,sizeof(top));
memset(son,0,sizeof(son));
memset(siz,0,sizeof(siz));
memset(fa,0,sizeof(fa));
memset(dep,0,sizeof(dep));
for(int i=1;i<=n;++i)
{
scanf("%d",&t[i].v);
t[i].p=i;
}
for(int i=1;i<n;++i)
{
scanf("%d%d",&X,&Y);
AddEdge(X,Y);
AddEdge(Y,X);
}
int all=n;
for(int i=1;i<=m;++i){
scanf("%d%d%d%d",&xs[i],&ys[i],&as[i],&bs[i]);
t[++all].v=as[i];
t[all].p=all;
t[++all].v=bs[i];
t[all].p=all;
}
sort(t+1,t+all+1);
if(t[1].p<=n){
a[t[1].p]=++zy;
}
else{
if((t[1].p-n)%2==1){
as[(t[1].p-n-1)/2+1]=++zy;
}
else{
bs[(t[1].p-n)/2]=++zy;
}
}
ma[zy]=t[1].v;
for(int i=2;i<=all;++i){
if(t[i].v!=t[i-1].v) ++zy;
if(t[i].p<=n){
a[t[i].p]=zy;
}
else{
if((t[i].p-n)%2==1){
as[(t[i].p-n-1)/2+1]=zy;
}
else{
bs[(t[i].p-n)/2]=zy;
}
}
ma[zy]=t[i].v;
}
root[0]=1;
BuildTree(root[0],1,zy);
df1(1);
top[1]=1;
df2(1);
dfs(1);
for(int i=1;i<=m;++i){
X=xs[i];
Y=ys[i];
int t=lca(X,Y);
printf("%lld%c",query(root[X],root[Y],root[t],root[fa[t]],as[i],bs[i],1,zy),i==m?'\n':' ');
}
}
return 0;
}

【主席树】【最近公共祖先】hdu6162 Ch’s gift的更多相关文章

  1. hdu6162 Ch’s gift

    地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=6162 题目: Ch’s gift Time Limit: 6000/3000 MS (Java ...

  2. 马路 树链剖分/线段树/最近公共祖先(LCA)

    题目 [问题描述] 小迟生活的城市是⼀棵树(树指的是⼀个含有 \(n\) 个节点以及 \(n-1\) 条边的⽆向连通图),节点编号从 \(1\) 到 \(n\),每条边拥有⼀个权值 \(value\) ...

  3. 【bzoj2588】Spoj 10628. Count on a tree 离散化+主席树

    题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个 ...

  4. Hihocoder #1067 : 最近公共祖先·二

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中 ...

  5. 51 nod 1681 公共祖先 (主席树+dfs序)

    1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题   有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另 ...

  6. 0x63树的直径与最近公共祖先

    凉 bzoj1999 先把树的直径求出来,从左往右枚举,对于当前位置i,找到满足限制并且最远的点j,当前位置最大值就是max(i~j区间内除直径外的子树路径长度最大值,1~i的长度,j~n的长度) 然 ...

  7. 线段树、最短路径、最小生成树、并查集、二分图匹配、最近公共祖先--C++模板

    线段树(区间修改,区间和): #include <cstdio> #include <iostream> #include <cstring> using name ...

  8. 【并查集】【树】最近公共祖先LCA-Tarjan算法

    最近公共祖先LCA 双链BT 如果每个结点都有一个指针指向它的父结点,于是我们可以从任何一个结点出发,得到一个到达树根结点的单向链表.因此这个问题转换为两个单向链表的第一个公共结点(先分别遍历两个链表 ...

  9. 洛谷P3379 【模板】最近公共祖先(LCA)(树链剖分)

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

随机推荐

  1. java 连接MySQL的代码

    1.java connect MySQL as conding. https://www.cnblogs.com/centor/p/6142775.html

  2. 获取子iframe框架的元素

    我们常常遇到使用iframe框的时候,该iframe框不能根据自己内部的内容撑起来的这种问题 必要条件:不能在跨域的情况下...本地可以放到localhost下进行测试 //父页面index.html ...

  3. bzoj 1030 ac自动机

    比较容易看出来先建立ac自动机,然后在自动机上做DP,设w[0..1][i][j]为当前不包括/包括字典中的字符串,当前在自动机中走到第i个节点,完成的文本的长度为j的方案数,那么比较容易的转移w[i ...

  4. 玩一下易语言 "和"字有多种读音,注定了它的重要性!!

    变量名 类型 静态 数组 备注 拼音 文本型   0   测试的汉字 文本型       有几种发音 整数型       i 整数型       测试用的汉字 = “和” 有几种发音 = 取发音数目 ...

  5. eCharts_基于eCharts开发的一个多图表页面

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. 《Linux内核原理与设计》第十一周作业 ShellShock攻击实验

    <Linux内核原理与设计>第十一周作业 ShellShock攻击实验 分组: 和20179215袁琳完成实验及博客攥写 实验内容:   Bash中发现了一个严重漏洞shellshock, ...

  7. 2018DDCTF Misc部分WP

    题目给出了这样一串字符:d4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9e1e6b3e3b9e4b3b7b7 ...

  8. c#上传文件时,当选择的文件为0kb,会验证不通过

    FileUpload1.HasFile 当FileUpload1控件选择的文件为0KB时,FileUpload1.HasFile返回false

  9. 81.Search in Rotated Sorted Array II---二分变形

    题目链接 题目大意:与33题类似,只是这里数组中有重复数值. 法一:解法与33题类似,只是这里要处理1,3,1,1,1这种情况,即有重复值时,mid与left和right都相等时,可以采用right- ...

  10. 浅谈分布式一致性与CAP/BASE/ACID理论

    ##转载请注明 CAP理论(98年秋提出,99年正式发表): C( Consistency)一致性:在分布式系统中,数据一致更新,所有数据变动都是同步的: A( Availability)可用性:分布 ...