JZOJ6362. 【NOIP2019模拟2019.9.18】数星星(star)

Description

在这里插入图片描述

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]);
}

posted @ 2019-09-21 14:28  Deep_Thinking  阅读(203)  评论(0编辑  收藏  举报