Description
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/cd438a23c9ddac7713170a873fc5fe24.png)
Solution
- 考虑分治,将每一个询问挂在包括它的最大的区间中。
- 只考虑中点往右的区间的贡献,那么每一个点对于覆盖它的最早的时间有一个贡献。
- 我们建一个虚树,并且用并查集路径压缩,即覆盖过的点不再走那么就可以保证时间了。
- 而覆盖的贡献我们记录在一个以时间为下标的树状数组中,便于之后的查询。
- 然后再考虑从中点往左边处理覆盖操作,并同时处理左端点在当前位置的询问。
- 但是我们注意到如果一个点在这里的覆盖中被覆盖到,那么其实右边的覆盖操作是无效的,所以要重新用一个并查集完成这个操作,并且如果当前点对于右边的某个时间有贡献,把它的贡献撤回,直接在当前算。
- 注意不但点要记录是否被覆盖,边也要记录是否被覆盖。
- 时间复杂度n log n2
- 另外还有LCT的简单做法,又短又快,我这个快要调晕了。。。。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 100005
#define maxp 17
#define ll long long
using namespace std;
int n,m,q,i,j,k,x,y,l,r;
int em,e[maxn*2],nx[maxn*2],ls[maxn];
int fa[maxn][maxp],dep[maxn],totd,dfn[maxn];
int u[maxn],v[maxn],lca[maxn],lq[maxn],rq[maxn],fr[maxn];
ll a[maxn],sum[maxn],ans[maxn];
int p[maxn];
int cmp(int a,int b){return fr[a]<fr[b]||fr[a]==fr[b]&&lq[a]>lq[b];}
int read(){
int x=0; char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
void insert(int x,int y){
em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
em++; e[em]=x; nx[em]=ls[y]; ls[y]=em;
}
void DFS(int x,int p){
fa[x][0]=p,dep[x]=dep[p]+1,sum[x]=sum[p]+a[x],dfn[x]=++totd;
for(int i=1;i<maxp;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p)
DFS(e[i],x);
}
int getlca(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for(int i=maxp-1;i>=0;i--) if (dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if (x==y) return x;
for(int i=maxp-1;i>=0;i--) if (fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int Lim;
struct Treearry{
ll s[maxn];
void add(int x,ll delta){for(;x<=Lim;x+=x&-x) s[x]+=delta;}
void clear(){for(int i=1;i<=Lim;i++) s[i]=0;}
ll sum(int x,ll S=0){for(;x;x-=x&-x) S+=s[x];return S;}
} T;
int que[maxn];
int cmp2(int a,int b){return lq[a]<lq[b];};
int bz[maxn],tot,d[maxn],now,cnt,f[maxn],Fa[maxn],b[maxn];
int mi[maxn],mi0[maxn],mx[maxn],mx0[maxn];
int cmp3(int a,int b){return dfn[a]<dfn[b];};
int father(int x){return (f[x]==x)?x:f[x]=father(f[x]);}
int cmp4(int a,int b){return lq[a]>lq[b];}
ll jump(int x,int p,int tim){
ll s=0; x=father(x);
while (dep[x]>dep[p]){
if (mi[x]==0) mi[x]=tim,s+=a[x];
mi0[x]=tim,s+=sum[x]-a[x]-max(sum[Fa[x]],sum[p]);
f[x]=Fa[x],x=father(Fa[x]);
}
return s;
}
ll jump0(int x,int p){
ll s=0; x=father(x);
while (dep[x]>dep[p]){
if (mi[x]) T.add(mi[x],-a[x]),mi[x]=0;
if (mi0[x]) {
T.add(mi0[x],-(sum[x]-a[x]-max(sum[Fa[x]],sum[p])));
mi0[x]=0;
}
if (!mx[x]) mx[x]=1,s+=a[x];
mx0[x]=1,s+=sum[x]-a[x]-max(sum[Fa[x]],sum[p]);
f[x]=Fa[x],x=father(Fa[x]);
}
return s;
}
void Doit(int l,int r,int t){
cnt=0;
for(;now<=q&&fr[p[now]]==t;now++)
que[++cnt]=p[now];
if (cnt){
int mid=(l+r)/2;
l=lq[que[1]],r=rq[que[1]];
for(int i=2;i<=cnt;i++)
l=min(l,lq[que[i]]),r=max(r,rq[que[i]]);
d[tot=1]=1,bz[1]=1;
for(int i=l;i<=r;i++) {
if (!bz[u[i]]) d[++tot]=u[i],bz[u[i]]=1;
if (!bz[v[i]]) d[++tot]=v[i],bz[v[i]]=1;
}
sort(d+1,d+1+tot,cmp3);
int totm=0,w=1; b[w]=d[1];
for(int i=2;i<=tot;i++){
int x=b[w],y=b[w-1],z=getlca(x,d[i]);
if (!bz[z]) d[tot+(++totm)]=z,bz[z]=1;
if (z==x) b[++w]=d[i]; else{
while (dfn[y]>dfn[z]){
Fa[x]=y,w--;
x=b[w],y=b[w-1],z=getlca(x,d[i]);
if (!bz[z]) d[tot+(++totm)]=z,bz[z]=1;
}
if (dfn[y]==dfn[z]) Fa[x]=y,w--; else
Fa[x]=z,b[w]=z;
b[++w]=d[i];
}
}
while (w>1) Fa[b[w]]=b[w-1],w--;
tot+=totm;
for(int i=1;i<=tot;i++) f[d[i]]=d[i];
Lim=r-mid;
for(int i=mid+1;i<=r;i++){
T.add(i-mid,jump(u[i],lca[i],i-mid)+jump(v[i],lca[i],i-mid)+(mi[lca[i]]==0)*a[lca[i]]);
if (mi[lca[i]]==0) mi[lca[i]]=i-mid;
}
for(int i=1;i<=tot;i++) f[d[i]]=d[i];
int now0=1; ll ss=0;
for(int i=mid;i>=l&&now0<=cnt;i--){
ss+=jump0(u[i],lca[i])+jump0(v[i],lca[i]);
if (mi[lca[i]]) T.add(mi[lca[i]],-a[lca[i]]),mi[lca[i]]=0;
if (!mx[lca[i]]) ss+=a[lca[i]],mx[lca[i]]=1;
for(;now0<=cnt&&lq[que[now0]]==i;now0++)
ans[que[now0]]=ss+T.sum(rq[que[now0]]-mid);
}
T.clear();for(int i=1;i<=tot;i++) bz[d[i]]=0;
for(int i=1;i<=tot;i++) mi[d[i]]=mi0[d[i]]=mx[d[i]]=mx0[d[i]]=0;
}
}
int he,ta,D0[maxn*20][3];
void Merge(){
he=0,ta=1;
D0[1][0]=1,D0[1][1]=m,D0[1][2]=1;
while (he<ta){
he++;
int l=D0[he][0],r=D0[he][1],mid=(l+r)/2,t=D0[he][2];
Doit(l,r,t);
if (l<r){
ta++,D0[ta][0]=l,D0[ta][1]=mid,D0[ta][2]=t*2;
ta++,D0[ta][0]=mid+1,D0[ta][1]=r,D0[ta][2]=t*2+1;
}
}
}
int main(){
freopen("star.in","r",stdin);
freopen("star.out","w",stdout);
n=read(),m=read(),q=read();
for(i=1;i<=n;i++) a[i]=read();
for(i=1;i<n;i++) x=read(),y=read(),insert(x,y);
DFS(1,0);
for(i=1;i<=m;i++) u[i]=read(),v[i]=read(),lca[i]=getlca(u[i],v[i]);
for(i=1;i<=q;i++) {
lq[i]=read(),rq[i]=read();
int l=1,r=m,t=1;
while (l<r){
int mid=(l+r)/2;
if (rq[i]<=mid) r=mid,t=t*2; else
if (lq[i]>mid) l=mid+1,t=t*2+1; else
{fr[i]=t;break;}
}
if (l==r) fr[i]=t;
p[i]=i;
}
sort(p+1,p+1+q,cmp);
now=1,Merge();
for(i=1;i<=q;i++) printf("%lld\n",ans[i]);
}