zoukankan      html  css  js  c++  java
  • 【51nod1792】Jabby's segment tree

    题目

    线段树是一种经典的数据结构,一颗[1,n]的线段树他的根是[1,n],当一个线段树的结点是[l,r]时,设mid=(l+r)>>1,则这个结点的左儿子右儿子分别是[l,mid],[mid+1,r]
    当我们在线段树上跑[x,y]询问时,一般是从根节点开始计算的,设现在所在结点是[l,r],有以下几种分支:
    1.若[x,y]包含[l,r],计算结束
    2.否则,若左儿子和[x,y]有交,计算左儿子,若右儿子和[x,y]有交,计算右儿子
    定义询问[x,y]的费用是询问时计算了几个结点
    给定Q次询问,每次给定l,r,求满足l<=x<=y<=r的(x,y)的费用之和
    你需要将答案对1000000007取模

    分析

    现将询问[l,r]挂在l上
    然后分治,
    假设当前做到区间[l,r]

    设ls[i]表示从[l,r]开始,往下跑线段树,跑区间[i,mid]的费用
    设rs[i]表示从[l,r]开始,往下跑线段树,跑区间[mid+1,i]的费用
    再设lc[i]表示从[l,r]开始,往下跑线段树,跑区间[x,y]其中i<=x<=y<=mid的总费用
    再设rc[i]表示从[l,r]开始,往下跑线段树,跑区间[x,y]其中mid+1<=x<=y<=i的总费用
    

    当有询问[l1,r1],l1在[l,mid]上,r1在[mid+1,r]上,就通过ls、rs、lc、rc就可以求出来
    然后将这四个数组往上传递就可以了

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <map>
    const int maxlongint=2147483647;
    const long long mo=1e9+7;
    const int N=100005;
    using namespace std;
    #define val(x,y) (1ll*(y-x+1)*(y-x+2)/2%mo)
    int la[N],ne[N],to[N],n,m,tot;
    long long lc[N],rc[N],ls[N],rs[N],ans[N],sum[N];
    void up(int l,int r,int mid)
    {
    	long long s=0;
    	for(int i=r;i>=mid+1;i--) (s+=rs[i])%=mo;
    	for(int i=r;i>=mid+1;i--) (lc[i]+=val(i,r))%=mo;
    	for(int i=mid,pp=0,pp1=0;i>=l;i--) pp1=lc[i],(lc[i]+=lc[i+1]-pp+s+ls[i]*(r-mid)%mo+(r-mid)+(mid-i+1)+mo)%=mo,pp=pp1;
    	lc[l]-=ls[l]+rs[r],(lc[l]+=mo)%=mo;
    
    	s=0;
    	for(int i=l;i<=mid;i++) (s+=ls[i])%=mo;
    	for(int i=l;i<=mid;i++) (rc[i]+=val(l,i))%=mo;
    	for(int i=mid+1,pp=0,pp1=0;i<=r;i++) pp1=rc[i],(rc[i]+=rc[i-1]-pp+s+rs[i]*(mid-l+1)%mo+(mid-l+1)+(i-mid)+mo)%=mo,pp=pp1;
    	rc[r]-=ls[l]+rs[r],(rc[l]+=mo)%=mo;
    
    	for(int i=r;i>=mid+1;i--) (++ls[i])%=mo;
    	for(int i=mid;i>=l;i--) (ls[i]+=ls[mid+1])%=mo;
    	for(int i=l;i<=mid;i++) (++rs[i])%=mo;
    	for(int i=mid+1;i<=r;i++) (rs[i]+=rs[mid])%=mo;
    	ls[l]=rs[r]=1;
    }
    void dg(int l,int r,int v)
    {
    	int mid=(l+r)>>1;
    	if(l==r)
    	{
    		ls[l]=rs[l]=lc[l]=rc[l]=1;
    		for(int i=l;i<=mid;i++)
    			for(int j=la[i];j;j=ne[j])
    				if(i==to[j]) ans[j]=v;
    		return;
    	}
    	dg(l,mid,v+1),dg(mid+1,r,v+1);
    	for(int i=l;i<=r;i++) sum[i]=0;
    	sum[mid]=ls[mid];for(int i=mid-1;i>=l;i--) sum[i]=sum[i+1]+ls[i]; 
    	sum[mid+1]=rs[mid+1];for(int i=mid+2;i<=r;i++) sum[i]=sum[i-1]+rs[i];
    	for(int i=l;i<=mid;i++)
    	{
    		for(int j=la[i];j;j=ne[j])
    		{
    			if(to[j]<=mid || to[j]>r) continue;
    			(ans[j]+=(val(i,to[j]))*v%mo+sum[i]*(to[j]-mid)%mo+(mid-i+1)*sum[to[j]]%mo+lc[i]+rc[to[j]])%=mo;
    			if(i==l && to[j]==r) (ans[j]-=ls[l]+rs[r]-mo*2)%=mo;
    		}
    	}
    	up(l,r,mid);
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int x,y,i=1;i<=m;i++)
    	{
    		scanf("%d%d",&x,&y);
    		ne[i]=la[x],la[x]=i,to[i]=y;
    	}
    	dg(1,n,1);
    	for(int i=1;i<=m;i++) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    依赖注入
    微服务下的安全方案
    VS2019 社区版(community) 离线版本 解决“试用30天过期”步骤
    webpack4升级webpack5
    Ubuntu 上 Node.js 安装和卸载
    记录一次使用locust压测的过程
    大厂面试通关指南,已拿腾讯,阿里offer(附100+最新大厂真题)
    通过自己整理和刷题三个月成功入职腾讯,皇天不负有心人啊!!
    不懂就问系列,为什么别人能靠这份面试题宝典去大厂?(内附面试题答案)
    整理了3家面试问题:美团+字节+腾讯,个个三面,你认为你能走到哪一面?
  • 原文地址:https://www.cnblogs.com/chen1352/p/9099482.html
Copyright © 2011-2022 走看看