BZOJ 4012: [HNOI2015]开店 -- 动态树分治

来源:互联网 发布:java return this 编辑:程序博客网 时间:2024/05/16 19:00

4012: [HNOI2015]开店

Time Limit: 70 Sec  Memory Limit: 512 MB
Submit: 1463  Solved: 635
[Submit][Status][Discuss]

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

Source


总算搞掉了一直挂在心里的题。。。

被题面吸引进来,跪着也要切掉。

构建好重心树后每个点维护:

以这个点为重心的块内年龄区间的距离和以及数量

以这个点为根到她到重心树上父亲的年龄区间的距离和以及数量

对于每个查询,在重心树上跳同时记录跳的距离,答案额外加上距离*该块内合法妖怪数量。

但是如果每个点建两棵线段树的话,就算动态开点,空间复杂度也是吃不消的。

因为仅需要支持区间求和,可以在建树时开两个vector,按年龄排序并处理前缀和,查询时二分即可。// sro PoPoQQQ orz

总复杂度O(nlog^2n+qlog^2n)

//另hzwer的点分治写法可以被卡,,不能保证重心树深度严格<= logn

代码丑死了(摔

#include<bits/stdc++.h>typedef long long ll;using namespace std;#define debug(x) cout<<#x<<"="<<x<<endlconst int maxn = 300009;int b[maxn],a[maxn],W[maxn],siz[maxn];int first[maxn];bool vis[maxn];struct edg{    int next;    int to;    int val;}e[maxn<<1];int e_sum;struct Info{int anc,idx;ll dis;};int n,m,A,tot,cnt,rt,sum;vector<Info> List[maxn];vector<pair<int,ll> > Mast[maxn],root[maxn];int c1[maxn],c2[maxn];inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}inline void add_edg(int x,int y,int z){    e_sum++;    e[e_sum].next=first[x];    first[x]=e_sum;    e[e_sum].to=y;    e[e_sum].val=z;}inline int Lower(int x){    int l=1,r=b[0],pos=b[0]+1;    while(l<=r)    {        int mid=(l+r)>>1;        if(b[mid]>=x){pos=mid;r=mid-1;}        else l=mid+1;    }return pos;}inline int Upper(int x){    int l=1,r=b[0],pos=0;    while(l<=r)    {        int mid=(l+r)>>1;        if(b[mid]<=x){pos=mid;l=mid+1;}        else r=mid-1;    }return pos;}pair<ll,int> ask_root(int idx,int left,int right){    int l=0,r=c2[idx],L=0,R=0;    while(l<=r)    {        int mid=(l+r)>>1;        if(root[idx][mid].first<=left){L=mid;l=mid+1;}        else r=mid-1;    }    l=0,r=c2[idx];    while(l<=r)    {        int mid=(l+r)>>1;        if(root[idx][mid].first<=right){R=mid;l=mid+1;}        else r=mid-1;    }    return make_pair(root[idx][R].second-root[idx][L].second,R-L);}pair<ll,int> ask_Mast(int idx,int left,int right){    int l=0,r=c1[idx],L=0,R=0;    while(l<=r)    {        int mid=(l+r)>>1;        if(Mast[idx][mid].first<=left){L=mid;l=mid+1;}        else r=mid-1;    }    l=0,r=c1[idx];    while(l<=r)    {        int mid=(l+r)>>1;        if(Mast[idx][mid].first<=right){R=mid;l=mid+1;}        else r=mid-1;    }    return make_pair(Mast[idx][R].second-Mast[idx][L].second,R-L);}void find(int x,int fa){    W[x]=0;siz[x]=1;    for(int i=first[x];i;i=e[i].next)    {        int w=e[i].to;        if(w==fa||vis[w]) continue;        find(w,x);        W[x]=max(W[x],siz[w]);        siz[x]+=siz[w];    }W[x]=max(W[x],sum-siz[x]);    if(W[x]<W[rt]) rt=x;}void calc(int x,int fa){    siz[x]=1;    for(int i=first[x];i;i=e[i].next)    {        int w=e[i].to;        if(w==fa||vis[w]) continue;        calc(w,x);        siz[x]+=siz[w];    }}void dfs(int x,int fa,int dis){    List[x].push_back((Info){rt,cnt,dis});    Mast[rt].push_back(make_pair(a[x],dis));c1[rt]++;    root[cnt].push_back(make_pair(a[x],dis));c2[cnt]++;    for(int i=first[x];i;i=e[i].next)    {        int w=e[i].to;        if(w==fa||vis[w]) continue;        dfs(w,x,dis+e[i].val);    }}void solve(int x){    vis[x]=1;    for(int i=first[x];i;i=e[i].next)    {        int w=e[i].to;        if(vis[w]) continue;        cnt++;dfs(w,x,e[i].val);        root[cnt].push_back(make_pair(0,0));        sort(root[cnt].begin(),root[cnt].end());        for(int i=1;i<root[cnt].size();i++) root[cnt][i].second+=root[cnt][i-1].second;    }    Mast[x].push_back(make_pair(0,0));sort(Mast[x].begin(),Mast[x].end());    for(int i=1;i<Mast[x].size();i++) Mast[x][i].second+=Mast[x][i-1].second;    for(int i=first[x];i;i=e[i].next)    {        int w=e[i].to;        if(vis[w]) continue;        rt=0;calc(w,x);sum=siz[w];        find(w,0);solve(rt);    }}ll query(int x,int l,int r){    if(l>r) return 0;    ll ans=ask_Mast(x,l-1,r).first,sz=List[x].size();    for(int i=0;i<sz;i++)    {        if(l<=a[List[x][i].anc]&&a[List[x][i].anc]<=r) ans+=List[x][i].dis;        pair<ll,int> L=ask_Mast(List[x][i].anc,l-1,r),R=ask_root(List[x][i].idx,l-1,r);        ans+=L.first+L.second*List[x][i].dis;        ans-=R.first+R.second*List[x][i].dis;    }return ans;}int main(){    n=read();m=read();A=read();    for(int i=1;i<=n;i++) a[i]=b[i]=read();    sort(b+1,b+1+n);b[0]=unique(b+1,b+1+n)-b-1;    for(int i=1;i<=n;i++) a[i]=Lower(a[i]);    for(int i=1;i<n;i++)    {        int x=read(),y=read(),z=read();        add_edg(x,y,z);add_edg(y,x,z);    }rt=0;W[0]=n+1;sum=n;    find(1,0);solve(rt);    ll last=0;    int x;ll L,R,l,r;    for(int i=1;i<=m;i++)    {        x=read();L=read(),R=read();        l=min((L+last)%A,(R+last)%A);r=max((L+last)%A,(R+last)%A);        printf("%lld\n",last=query(x,Lower((int)l),Upper((int)r)));        last%=(ll)A;    }    return 0;}


1 0
原创粉丝点击