【BZOJ4012】開店(主席樹)
阿新 • • 發佈:2018-01-06
void while -- div mat 但是 很多 .html 也有
比較喜歡可愛的東西。幽香通過研究發現,基本上妖怪的興趣只跟年齡有關,所以
幽香打算選擇一個地方 u(u為編號),然後在 u開一家面向年齡在 L到R 之間(即
年齡大於等於 L、小於等於 R)的妖怪的店。也有可能 u這個地方離這些妖怪比較
遠,於是幽香就想要知道所有年齡在 L 到 R 之間的妖怪,到點 u 的距離的和是多
少(妖怪到 u 的距離是該妖怪所在地方到 u 的路徑上的邊的權之和) ,幽香把這個
稱為這個開店方案的方便值。幽香她們還沒有決定要把店開在哪裏,八雲紫倒是準
備了很多方案,於是幽香想要知道,對於每個方案,方便值是多少呢。
怪的年齡上限。
第二行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)。
【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),
前行的 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\n",ans);
}
return 0;
}
【BZOJ4012】開店(主席樹)