zoukankan      html  css  js  c++  java
  • 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
    ",ans[i]);
    }
    
    
  • 相关阅读:
    SVN 安装 使用指南
    使用angular-cli快速搭建项目命令
    angular 路由的引用
    c#默认类的修饰符。
    c#
    js改变dom对象样式
    jquery常用函数
    PHP 文件上传
    php 表单代码
    Python 条件语句
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090960.html
Copyright © 2011-2022 走看看