HDU 6162 Ch’s gift
线段树,离线
题意
给一棵树,每次询问:uv两点间的路上(包括uv),点权在ab之间的所有点点权和。
思路
由于没有修改操作,一个显然的想法是离线处理所有问题
将询问拆成1-x,1-y,1-LCA(x,y),则处理的问题转化为从根到节点的链上的问题。
解决这个问题,我们可以在dfs时向treap插入当前的数,在退出时删除这个数,并且每次维护在该点上的答案。
两种思路,在线的树链剖分加主席树维护,离线的LCA加线段树/treap。我写的是离线LCA加线段树。线段树当成权值线段树用,所以离散化特别麻烦,可能treap更简单。
将每个询问拆开,u到v拆成:(1~u)+(1~v)-(2*1~LCA(u,v))+LCA(u,v)。如果LCA(u,v)权在询问上下界之间,就作为附加值加上,否则不加。
因为权值线段树要求范围是1到n,所以需要离散化,注意各种边界问题。
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<set>
#include<iostream>
#include<vector>
#include<queue>
#include<regex>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=100005;
const int oo=0x3f3f3f3f;
typedef long long LL;
//树结构
struct Edge
{
int to, ne;
}e[MAXN<<1];
int head[MAXN], v[MAXN], edgenum;
void addedge(int u, int v)
{
e[edgenum].to=v, e[edgenum].ne=head[u], head[u]=edgenum++;
e[edgenum].to=u, e[edgenum].ne=head[v], head[v]=edgenum++;
}
//LCA
int parent[20][MAXN];
int depth[MAXN];
void ddfs(int v, int p, int d)
{
parent[0][v]=p;
depth[v]=d;
for(int i=head[v];~i;i=e[i].ne)
{
if(e[i].to!=p) ddfs(e[i].to, v, d+1);
}
}
void init(int V)
{
ddfs(1, -1, 0);
for(int k=0;k+1<20;k++)
{
for(int v=1;v<=V;v++)
{
if(parent[k][v]<0) parent[k+1][v]=-1;
else parent[k+1][v]=parent[k][parent[k][v]];
}
}
}
int lca(int u, int v)
{
if(depth[u]>depth[v]) swap(u, v);
for(int k=0;k<20;k++)
{
if((depth[v]-depth[u])>>k&1)
v=parent[k][v];
}
if(u==v) return u;
for(int k=20-1;k>=0;k--)
{
if(parent[k][u]!=parent[k][v])
{
u=parent[k][u];
v=parent[k][v];
}
}
return parent[0][u];
}
//点权与哈希
struct Val
{
LL val;
int i;
int ha;
}val[MAXN];
bool cmp1(Val a, Val b)
{
return a.val<b.val;
}
bool cmp2(Val a, Val b)
{
return a.i<b.i;
}
LL ha[MAXN];
//分解询问
struct Query
{
int x, y;
int i, k;
LL res;
int ne;
int up, dw;
LL add;
}q[MAXN*3];
int qnum, headq[MAXN];//链式前向星储存询问
//线段树
LL stree[MAXN<<2];
void pushup(int rt) { stree[rt]=stree[rt<<1]+stree[rt<<1|1]; }
void build() { M(stree, 0); }
void update(int pos, LL c, int l, int r, int rt)
{
if(l==r) { stree[rt]+=c;return; }
int mid=(l+r)>>1;
if(pos<=mid) update(pos, c, lson);
else update(pos, c, rson);
pushup(rt);
}
LL query(int L, int R, int l, int r, int rt)
{
if(L<=l&&r<=R) return stree[rt];
int mid=(l+r)>>1;
LL res=0;
if(L<=mid) res+=query(L, R, lson);
if(mid<R) res+=query(L, R, rson);
return res;
}
//dfs的solve
void dfs(int u, int fa, int n)
{
update(val[u].ha, val[u].val, 1, n, 1);
for(int i=headq[u];~i;i=q[i].ne)
{
int l=q[i].dw, r=q[i].up;
q[i].res=query(l, r, 1, n, 1);
}
for(int i=head[u];~i;i=e[i].ne)
{
int to=e[i].to;
if(to!=fa) dfs(to, u, n);
}
update(val[u].ha, -val[u].val, 1, n, 1);
}
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("ou.txt", "w", stdout);
int n, m;
while(scanf("%d%d", &n, &m)==2)
{
//初始化
edgenum=1, qnum=1;M(head, -1), M(headq, -1);
build();
//点权与哈希
for(int i=1;i<=n;i++)
{
scanf("%lld", &val[i].val), val[i].i=i;
}
sort(val+1, val+n+1, cmp1);
int tt=1;ha[tt]=val[1].val-1;tt++;//加前哨兵
val[1].ha=tt;ha[tt]=val[1].val;
for(int i=2;i<=n;i++)
{
if(val[i].val>val[i-1].val) val[i].ha=++tt, ha[tt]=val[i].val;
else val[i].ha=tt;
}
sort(val+1, val+n+1, cmp2);
//树结构
for(int i=1;i<n;i++)
{
int u, v;scanf("%d%d", &u, &v);
addedge(u, v);
}
init(n);//LCA初始化
//分解询问
for(int i=1;i<=m;i++)
{
int x, y, up, dw;scanf("%d%d%d%d", &x, &y, &dw, &up);
int u=lca(x, y);
q[qnum].x=1, q[qnum].y=x, q[qnum].i=i, q[qnum].k=1;
q[qnum].dw=lower_bound(ha+1, ha+1+tt, dw)-ha, q[qnum].up=lower_bound(ha+1, ha+1+tt, up)-ha;
if(up<ha[q[qnum].up]) q[qnum].up--;//注意特判上端点
q[qnum].ne=headq[x], headq[x]=qnum++;
q[qnum].x=1, q[qnum].y=y, q[qnum].i=i, q[qnum].k=1;
q[qnum].dw=lower_bound(ha+1, ha+1+tt, dw)-ha, q[qnum].up=lower_bound(ha+1, ha+1+tt, up)-ha;
if(up<ha[q[qnum].up]) q[qnum].up--;//注意特判上端点
q[qnum].ne=headq[y], headq[y]=qnum++;
q[qnum].x=1, q[qnum].y=u, q[qnum].i=i, q[qnum].k=-1;
q[qnum].dw=lower_bound(ha+1, ha+1+tt, dw)-ha, q[qnum].up=lower_bound(ha+1, ha+1+tt, up)-ha;
if(up<ha[q[qnum].up]) q[qnum].up--;//注意特判上端点
q[qnum].ne=headq[u], headq[u]=qnum++;
q[qnum-1].add=((val[u].val>=dw&&val[u].val<=up) ? val[u].val : 0);//是否附加LCA的权
}
dfs(1, -1, tt);
for(int i=1;i<=3*m;i+=3)
{
LL ans=q[i].res+q[i+1].res-2*q[i+2].res+q[i+2].add;
printf("%lld%c", ans, i==3*m-2 ? '\n' : ' ');
}
}
//system("pause");
return 0;
}