题意:一棵树,每个点有个权值,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?' ':' '); } } return 0; }