zoukankan      html  css  js  c++  java
  • 【BZOJ4012】开店(主席树)

    【BZOJ4012】开店(主席树)

    题面

    Description

    风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到
    人生哲学。最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱。这样的
    想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面
    向什么样的人群。很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n
    个地方,编号为 1 到 n,被 n-1 条带权的边连接起来。每个地方都住着一个妖怪,
    其中第 i 个地方的妖怪年龄是 x_i。妖怪都是些比较喜欢安静的家伙,所以它们并
    不希望和很多妖怪相邻。所以这个树所有顶点的度数都小于或等于 3。妖怪和人一
    样,兴趣点随着年龄的变化自然就会变化,比如我们的 18 岁少女幽香和八云紫就
    比较喜欢可爱的东西。幽香通过研究发现,基本上妖怪的兴趣只跟年龄有关,所以
    幽香打算选择一个地方 u(u为编号),然后在 u开一家面向年龄在 L到R 之间(即
    年龄大于等于 L、小于等于 R)的妖怪的店。也有可能 u这个地方离这些妖怪比较
    远,于是幽香就想要知道所有年龄在 L 到 R 之间的妖怪,到点 u 的距离的和是多
    少(妖怪到 u 的距离是该妖怪所在地方到 u 的路径上的边的权之和) ,幽香把这个
    称为这个开店方案的方便值。幽香她们还没有决定要把店开在哪里,八云紫倒是准
    备了很多方案,于是幽香想要知道,对于每个方案,方便值是多少呢。

    Input

    第一行三个用空格分开的数 n、Q和A,表示树的大小、开店的方案个数和妖
    怪的年龄上限。
    第二行n个用空格分开的数 x_1、x_2、…、x_n,x_i 表示第i 个地点妖怪的年
    龄,满足0<=x_i<A。(年龄是可以为 0的,例如刚出生的妖怪的年龄为 0。)
    接下来 n-1 行,每行三个用空格分开的数 a、b、c,表示树上的顶点 a 和 b 之
    间有一条权为c(1 <= c <= 1000)的边,a和b 是顶点编号。
    接下来Q行,每行三个用空格分开的数 u、 a、 b。对于这 Q行的每一行,用 a、
    b、A计算出 L和R,表示询问“在地方 u开店,面向妖怪的年龄区间为[L,R]的方
    案的方便值是多少”。对于其中第 1 行,L 和 R 的计算方法为:L=min(a%A,b%A),
    R=max(a%A,b%A)。对于第 2到第 Q行,假设前一行得到的方便值为 ans,那么当
    前行的 L 和 R 计算方法为: L=min((a+ans)%A,(b+ans)%A),
    R=max((a+ans)%A,(b+ans)%A)。

    Output

    对于每个方案,输出一行表示方便值。

    Sample Input

    10 10 10

    0 0 7 2 1 4 7 7 7 9

    1 2 270

    2 3 217

    1 4 326

    2 5 361

    4 6 116

    3 7 38

    1 8 800

    6 9 210

    7 10 278

    8 9 8

    2 8 0

    9 3 1

    8 0 8

    4 2 7

    9 7 3

    4 7 0

    2 2 7

    3 2 1

    2 3 4

    Sample Output

    1603

    957

    7161

    9466

    3232

    5223

    1879

    1669

    1282

    0

    HINT

    满足 n<=150000,Q<=200000。对于所有数据,满足 A<=10^9

    题解

    这道题目和BZOJ3626 LCA很相似
    所以现在就可以考虑像上面那道题目一样的
    向链上打标记
    但是考虑到有年龄的限制
    所以需要用主席树
    还有就是空间可能开不下
    要标记永久化

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define MAX 200000
    #define ll long long
    inline int read()
    {
    	int x=0,t=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return x*t;
    }
    struct Line
    {
    	int v,next,w;
    }e[MAX<<1];
    int h[MAX],cnt=1;
    inline void Add(int u,int v,int w)
    {
    	e[cnt]=(Line){v,h[u],w};h[u]=cnt++;
    }
    int n,Q,A,Age[MAX],S[MAX],tot;
    /***********************************************************************/
    int dfn[MAX],dis[MAX],top[MAX],size[MAX],hson[MAX],fa[MAX];
    int tim,ln[MAX];
    void dfs1(int u,int ff)
    {
    	fa[u]=ff;size[u]=1;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(v==ff)continue;
    		dis[v]=dis[u]+e[i].w;
    		dfs1(v,u);
    		size[u]+=size[v];
    		if(size[v]>size[hson[u]])hson[u]=v;
    	} 
    }
    void dfs2(int u,int tp)
    {
    	top[u]=tp;dfn[u]=++tim;ln[tim]=u;
    	if(hson[u])dfs2(hson[u],tp);
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(v==fa[u]||v==hson[u])continue;
    		dfs2(v,v);
    	}
    }
    /***********************************************************************/
    struct Node
    {
    	int ls,rs;
    	ll sum;
    	ll lz;
    }t[MAX<<6];
    int Cnt;
    bool cmp(int a,int b){return Age[a]<Age[b];}
    void Build(int &now,int l,int r)
    {
    	now=++Cnt;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	Build(t[now].ls,l,mid);
    	Build(t[now].rs,mid+1,r);
    }
    void Modify(int &now,int l,int r,int al,int ar)
    {
    	t[++Cnt]=t[now];now=Cnt;
    	t[now].sum+=dis[ln[ar]]-dis[fa[ln[al]]];
    	if(l==al&&r==ar){t[now].lz++;return;}
    	int mid=(l+r)>>1;
    	if(ar<=mid)Modify(t[now].ls,l,mid,al,ar);
    	else if(al>mid)Modify(t[now].rs,mid+1,r,al,ar);
    	else
    	{
    		Modify(t[now].ls,l,mid,al,mid);
    		Modify(t[now].rs,mid+1,r,mid+1,ar);
    	}
    }
    ll Query(int now,int l,int r,ll ly,int al,int ar)
    {
    	if(l==al&&r==ar)return t[now].sum+1ll*ly*(dis[ln[ar]]-dis[fa[ln[al]]]);
    	int mid=(l+r)>>1;
    	if(ar<=mid)return Query(t[now].ls,l,mid,ly+t[now].lz,al,ar);
    	if(al>mid)return Query(t[now].rs,mid+1,r,ly+t[now].lz,al,ar);
    	return Query(t[now].ls,l,mid,ly+t[now].lz,al,mid)+Query(t[now].rs,mid+1,r,ly+t[now].lz,mid+1,ar);
    }
    /***********************************************************************/
    ll sdis[MAX];
    int rt[MAX],id[MAX];
    ll Calc(int u,int K)
    {
    	ll ret=0;
    	while(top[u]!=1)ret+=Query(rt[K],1,n,0,dfn[top[u]],dfn[u]),u=fa[top[u]];
    	ret+=Query(rt[K],1,n,0,1,dfn[u]);
    	return ret;
    }
    int main()
    {
    	n=read();Q=read();A=read();
    	for(int i=1;i<=n;++i)id[i]=i,Age[i]=read(),S[++tot]=Age[i];
    	sort(&S[1],&S[n+1]);
    	sort(&id[1],&id[n+1],cmp);
    	for(int i=1;i<n;++i)
    	{
    		int u=read(),v=read(),C=read();
    		Add(u,v,C);Add(v,u,C);
    	}
    	dfs1(1,0);dfs2(1,1);
    	Build(rt[0],1,n);
    	for(int i=1;i<=n;++i)
    	{
    		int x=id[i];
    		sdis[i]=sdis[i-1]+dis[x];
    		rt[i]=rt[i-1];
    		while(top[x]!=1)
    			Modify(rt[i],1,n,dfn[top[x]],dfn[x]),x=fa[top[x]];
    		Modify(rt[i],1,n,1,dfn[x]);
    	}
    	ll ans=0;
    	int L,R;
    	while(Q--)
    	{
    		ll u=read(),a=read(),b=read();
    		L=min((ans+a)%A,(ans+b)%A);
    		R=max((ans+a)%A,(ans+b)%A);
    		L=lower_bound(&S[1],&S[tot+1],L)-S;
    		R=lower_bound(&S[1],&S[tot+1],R+1)-S-1;
    		ans=1ll*(R-L+1)*dis[u]+sdis[R]-sdis[L-1]-2ll*(Calc(u,R)-Calc(u,L-1));
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    javascript、jQuery的扩展方法,扩展实例展示代码
    经典弹出层Colorbox
    在Entity Framework中使用事务
    WCF中常用的binding方式
    前端上传组件Plupload使用指南
    SQL ROW_NUMBER() OVER函数的基本用法用法
    数据库选项--触发器
    数据库选项--会刷新过程缓存的选项
    数据库选项--页面检查
    数据库选项--自动更新统计
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8213728.html
Copyright © 2011-2022 走看看