题意:一棵树,每个点有个权值,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. PAT L1-009 N个数求和(运用GCD进行通分)

    题目链接:https://www.patest.cn/contests/gplt/L1-009 题目: 本题的要求很简单,就是求N个数字的和.麻烦的是,这些数字是以有理数“分子/分母”的形式给出的,你 ...

  2. python3中处理url异常

    import urllib.request import urllib.error url = 'http://c.telunyun.com/Chart/getJsonData?market=1' d ...

  3. 网络知识===wireshark抓包出现“TCP segment of a reassembled PDU”的解释(载)

    网上胡说八道,众说风云,感觉这篇还算靠谱点. 原文链接:http://blog.csdn.net/dog250/article/details/51809566 为什么大家看到这个以后总是会往MSS, ...

  4. BZOJ 3771 生成函数,FFT

    Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: “这把斧头,是不是你的?” 樵夫一看:“是啊是啊!” 水神把斧头扔在一 ...

  5. apache的扩展模块安装

    /* 当需要用到Apache的扩展模块时, 就要用到了apache的扩展工具 apxs */ #在使用这个功能之前,请先确认是否已经加载了 mod_so 模块,方法是: [root@localhost ...

  6. jq监听ajax执行开始,出错,结束。

    $(“#msg”).ajaxComplete(function(event,request, settings){   $(this).append(“<li>请求完成.</li&g ...

  7. linux删除乱码文件[转载]

    一些乱码文件不可以通过普通的rm命令进行管理.可以通过删除i节点的方式删除. [root@192_168_100_35 musicwap]# ls??,?K?k?ͨa*.?J]?k?Φ??P???Z? ...

  8. hdu5740

    考验代码能力的题目,感觉网络流一要求输出方案我就写的丑 http://www.cnblogs.com/duoxiao/p/5777632.html 官方题解写的很详细 因为如果一个点染色确定后,整个图 ...

  9. Django2.x版本路由系统的正则写法以及视图函数的返回问题

    一.关于url.py urlpatterns每个元素的不再用url(),而是path(),最重要的一点是,正则的使用需要你自己手动导入re_path,并且在每个使用正则匹配的的元素用re_path() ...

  10. rpm包管理和源码包管理

    (1)软件类型 源码包 需要gcc编译 nginx-1.12.1.tar.gz 二进制包 已编译 mysql-community-common-5.7.12-1.el7.x86_64.rpm 常见的二 ...