• 【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;
    }
    
    
  • 相关阅读:
    JZOJ 3034. 【NOIP2012模拟10.17】独立集
    JZOJ 3035. 【NOIP2012模拟10.17】铁轨
    JZOJ 1259. 牛棚安排
    数位DP JZOJ 3316. 非回文数字
    JZOJ 3046. 游戏
    JZOJ 3013. 填充棋盘
    debian 安装oracle提供的java8
    java 汉字转拼音 PinYin4j
    debian ssh设置root权限登陆 Permission denied, please try again
    java并发下订单生成策略
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8213728.html
Copyright © 2020-2023  润新知