BZOJ 4012: [HNOI2015]开店 -- 动态树分治
来源:互联网 发布:java return this 编辑:程序博客网 时间:2024/05/16 19:00
4012: [HNOI2015]开店
Time Limit: 70 Sec Memory Limit: 512 MBSubmit: 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
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
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
- 【动态树分治】【bzoj 4012】: [HNOI2015]开店
- BZOJ 4012: [HNOI2015]开店 -- 动态树分治
- BZOJ 4012 HNOI2015 开店 动态树分治+二分
- [动态树分治] BZOJ4012 [HNOI2015]开店
- BZOJ-4012 开店(动态树分治)
- BZOJ 4012: [HNOI2015]开店
- BZOJ 4012 [HNOI2015]开店
- bzoj 4012 [HNOI2015]开店 【树链剖分】
- bzoj 4012: [HNOI2015]开店 (树链剖分+主席树)
- BZOJ 4012 HNOI 2015 开店 动态点分治
- 4012: [HNOI2015]开店
- [BZOJ]4012: [HNOI2015]开店 树链剖分+主席树(线段树合并)
- 【HNOI2015】开店
- HNOI2015 开店
- HNOI2015开店
- 【HNOI2015】开店
- bzoj4012开店 动态点分治
- [BZOJ4012][HNOI2015]开店-树链剖分-主席树
- kali2016.2安装wingide6.0.2
- HTML5 自定义属性 data-* 和 jQuery.data 详解
- Regular Expression Matching(LeedCode)
- archetype:create-from-project命令创建maven模板工程(自定义项目模板并且上载到maven私服)
- AndroidStudio多渠道打包
- BZOJ 4012: [HNOI2015]开店 -- 动态树分治
- Java: synchronized详解,静态同步方法,普通同步方法,同步代码块
- JSP中文乱码解决方法
- Spring 对JDBC的支持
- HDU-3045 Picnic Cows 【DP+斜率优化】
- 【NOIP2010 模拟赛】晨跑路径
- 设计模式
- HDU 2154 跳舞毯
- Android jni开发资料--NDK环境搭建和应用(深入浅出)