• bzoj4012: [HNOI2015]开店


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4012

    思路:首先我们考虑一个简化的问题:

    给定一棵树,每次询问所有点到一个点的距离和。


    画个图就能知道:距离和=所有点到根的距离和+点数*u到根的距离-每个点与u的lca到根的距离*2


    于是问题就成了求lca的dis和


    那么我们先对每个点,把它到根的路径覆盖一次,然后询问点u时就是从u向上跳,每次加覆盖次数*边权

    用树链剖分即可

    但是现在每个点多了一个点权,有了限制条件:只计算点权要在[l,r]内的点到u的距离。

    对于区间最大最小等问题我们用的是线段树,对于区间内且权值在[a,b]间的点的询问,我们就用可持久化线段树。


    这题也一样,先按点权(年龄)从小到大排序,离散化,按点权顺序把每个点到根的路径覆盖一次。

    像对序列的问题一样,询问年龄在[l,r]中的lca的dis和,就是[1,r]的距离和-[1,l]的距离和。

    然后就没有然后了


    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=150010,maxm=300010,maxt=10000010;
    typedef long long ll;
    using namespace std;
    int n,m,mod,age[maxn],pre[maxm],now[maxn],son[maxm],val[maxm],tot,tim;
    int last[maxn],root[maxn],rt; ll ans,sumdis[maxn],sumE[maxn],dis[maxn];
    int top[maxn],dep[maxn],hson[maxn],dfn[maxn],fa[maxn],siz[maxn];
    struct Monster{int age,id;}mon[maxn];
    void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
    bool operator<(Monster a,Monster b){return a.age!=b.age?a.age<b.age:a.id<b.id;}
    
    struct TSegment_tree{
    	ll sum[maxt];int ls[maxt],rs[maxt],tot,time[maxt];
    	int modify(int p,int l,int r,int a,int b){
    		int x=++tot,mid=(l+r)>>1;
    		ls[x]=ls[p],rs[x]=rs[p],sum[x]=sum[p],time[x]=time[p];
    		if (l==a&&r==b){time[x]++;return x;}
    		sum[x]+=(sumE[b]-sumE[a-1]);
    		if (b<=mid) ls[x]=modify(ls[x],l,mid,a,b);
    		else if (a>mid) rs[x]=modify(rs[x],mid+1,r,a,b);
    		else ls[x]=modify(ls[x],l,mid,a,mid),rs[x]=modify(rs[x],mid+1,r,mid+1,b);
    		return x;
    	}
    	ll query(int p,int l,int r,int a,int b){
    		ll res=1ll*(sumE[b]-sumE[a-1])*time[p];
    		if (l==a&&r==b){return res+sum[p];}
    		int mid=(l+r)>>1;
    		if (b<=mid) return res+query(ls[p],l,mid,a,b);
    		else if (a>mid) return res+query(rs[p],mid+1,r,a,b);
    		else return res+query(ls[p],l,mid,a,mid)+query(rs[p],mid+1,r,mid+1,b);
    	}
    }T;
    
    void dfs(int x){
    	siz[x]=1;
    	for (int y=now[x];y;y=pre[y])if (son[y]!=fa[x]){
    		fa[son[y]]=x,dis[son[y]]=dis[x]+val[y],last[son[y]]=val[y];
    		dfs(son[y]),siz[x]+=siz[son[y]];
    		if (siz[son[y]]>siz[hson[x]]) hson[x]=son[y];
    	}
    }
    
    void btree(int x,int tp){
    	sumE[dfn[x]=++tim]=last[x],top[x]=tp;
    	if (hson[x]) btree(hson[x],tp);
    	for (int y=now[x];y;y=pre[y])
    		if (hson[x]!=son[y]&&son[y]!=fa[x])
    			btree(son[y],son[y]);
    }
    
    int modify(int x){
    	while (top[x]!=1){rt=T.modify(rt,1,n,dfn[top[x]],dfn[x]),x=fa[top[x]];}
    	return rt=T.modify(rt,1,n,1,dfn[x]);
    }
    
    ll query(int rt,int x){
    	ll res=0;
    	while (top[x]!=1){res+=T.query(rt,1,n,dfn[top[x]],dfn[x]),x=fa[top[x]];}
    	return res+T.query(rt,1,n,1,dfn[x]);
    }
    
    int main(){
    	scanf("%d%d%d",&n,&m,&mod);
    	for (int i=1;i<=n;i++) scanf("%d",&mon[i].age),mon[i].id=i;
    	sort(mon+1,mon+1+n);
    	for (int i=1,a,b,c;i<n;i++) scanf("%d%d%d",&a,&b,&c),add(a,b,c),add(b,a,c);
    	dfs(1),btree(1,1);
    	for (int i=1;i<=n;i++) sumE[i]+=sumE[i-1],sumdis[i]=sumdis[i-1]+dis[mon[i].id];
    	for (int i=1;i<=n;i++) root[i]=modify(mon[i].id);
    	for (int i=1,a,b,u;i<=m;i++){
    		scanf("%d%d%d",&u,&a,&b);
    		a=(1ll*a+ans)%mod,b=(1ll*b+ans)%mod;
    		if (a>b) swap(a,b);
    		a=lower_bound(mon+1,mon+1+n,(Monster){a,0})-mon,b=upper_bound(mon+1,mon+1+n,(Monster){b,(int)1e9})-mon-1;
    		ans=1ll*(b-a+1)*dis[u]+sumdis[b]-sumdis[a-1]-2ll*((query(root[b],u)-query(root[a-1],u)));
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }






  • 相关阅读:
    SpringBoot2.x前后端分离跨域问题及Swagger不能访问
    SpirngBoot2.x整合Swagger2接口文档
    SpringBoot2.x整合Druid数据源
    SpringBoot2.x整合logback 实现自动打印日志
    docker 进入 mysql中的操作
    Intellij Springboot (子模块)访问jsp页面404
    运行rabbitmq 的docker
    mybatis拦截器修改sql重新set后不生效?
    oracle+mybatis如何在新增时返回主键(自增序列)的值?
    oracle+mybatis报“未找到要求的from关键字”错误?
  • 原文地址:https://www.cnblogs.com/thythy/p/5493498.html
Copyright © 2020-2023  润新知