BZOJ 4012 HNOI2015 开店 树的边分治

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4012

题意概述:给出一颗N点的树,保证树上所有点的度不超过3,树上每个点有权值,每条边有权值,现在有Q组询问,每组给出信息u,L,R,问点权在区间[L,R]的点到点u的距离和为多少。强制在线。

N<=150000,Q<=200000.

可能这是我这几天做过的题里面最水但是最码的一个了。。。。

实际上看见树上所有点的度不超过3就感觉可以用边分治做,具体的思路实际上很简单,建立一个边分治结构,这个结构大约有logN层,每层有N个点,对于每组询问,看询问的点u在当前树被分成的两棵子树中的哪一棵,统计出另一个子树中所有点权在询问区间内的点到u的距离,然后递归到u所在的子树,最终就可以计算出答案。

重点在于实现,一不小心处理的时候就会多写出几个常数出来。。。(不要问我是怎么知道的)

实际上这个题我yy的东西重点就在于把边分治建立成一个二叉树的结构然后在里面去搞事情(小火车万岁!),最多有2N个分治结构(每条边会产生2个,有N-1条边)。每一层每个点只会有一个信息,利用这个性质可以记录很多东西,询问的时候在分治结构中递归,令当前分治结构中询问点所在的子树根节点为x,另一边的子树根节点为y(实际上就是断掉的边的两个端点),每一次询问的时候就在y的信息里面二分计算询问区间内点到y的距离,同时得到这些点的数量,然后把从y经过x到u的距离补全累加到答案中,递归。(要点已经交代完了,剩下的请各位自己yy,手动滑稽)

预处理可以用归并排序做到O(nlogn),主要复杂度在查询,单次是O(log2n)。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<set>
  9 #include<map>
 10 #include<vector>
 11 #include<cctype>
 12 using namespace std;
 13 const int maxn=150005;
 14 const int maxd=45;
 15 typedef long long LL;
 16
 17 int N,Q,A,L,R,age[maxn]; LL ans,dist[maxd][maxn];
 18 struct edge{ int to,next,w; }E[maxn<<1];
 19 struct data{ int id,a; LL b; }D[maxd][maxn]; int cnt;
 20 int first[maxn],np,sz[maxn],rt[maxd][maxn];
 21 int ke[maxn<<1],MAX,ch[maxn<<1][2],l[maxn<<1],r[maxn<<1],size[maxd],tot[maxn<<1];
 22 bool vis[maxn<<1];
 23
 24 void _scanf(int &x)
 25 {
 26     x=0;
 27     char cha=getchar();
 28     while(cha<‘0‘||cha>‘9‘) cha=getchar();
 29     while(cha>=‘0‘&&cha<=‘9‘) x=x*10+cha-‘0‘,cha=getchar();
 30 }
 31 int out_cnt,out[22];
 32 void _printf(LL x)
 33 {
 34     out_cnt=0;
 35     out[++out_cnt]=x%10,x/=10;
 36     while(x) out[++out_cnt]=x%10,x/=10;
 37     while(out_cnt) putchar(‘0‘+out[out_cnt--]);
 38 }
 39 void add_edge(int u,int v,int w)
 40 {
 41     E[++np]=(edge){v,first[u],w};
 42     first[u]=np;
 43 }
 44 void data_in()
 45 {
 46     _scanf(N);_scanf(Q);_scanf(A);
 47     for(int i=1;i<=N;i++) _scanf(age[i]);
 48     int x,y,z;
 49     for(int i=1;i<N;i++){
 50         _scanf(x);_scanf(y);_scanf(z);
 51         add_edge(x,y,z);
 52         add_edge(y,x,z);
 53     }
 54 }
 55 void DFS1(int i,int f,int SZ,int id)
 56 {
 57     sz[i]=1;
 58     for(int p=first[i];p;p=E[p].next){
 59         int j=E[p].to;
 60         if(j==f||vis[p]) continue;
 61         DFS1(j,i,SZ,id);
 62         sz[i]+=sz[j];
 63         int tmp=max(sz[j],SZ-sz[j]);
 64         if(tmp<MAX) MAX=tmp,ke[id]=p;
 65     }
 66 }
 67 void DFS2(int i,int f,int d,LL l)
 68 {
 69     size[d]++,dist[d][i]=l;
 70     for(int p=first[i];p;p=E[p].next){
 71         int j=E[p].to;
 72         if(j==f||vis[p]) continue;
 73         rt[d][j]=rt[d][i];
 74         DFS2(j,i,d,l+E[p].w);
 75     }
 76 }
 77 bool cmp(data x,data y) { return x.a<y.a; }
 78 void merge_sort(int x,int d)
 79 {
 80     int pos=l[x],i=l[ch[x][0]],j=r[ch[x][0]],r1=r[ch[x][0]],r2=r[ch[x][1]];
 81     while(i<r1&&j<r2) D[d][pos++]=cmp(D[d+1][i],D[d+1][j])?D[d+1][i++]:D[d+1][j++];
 82     while(i<r1) D[d][pos++]=D[d+1][i++];
 83     while(j<r2) D[d][pos++]=D[d+1][j++];
 84 }
 85 void div_tree(int i,int SZ,int id,int d)
 86 {
 87     if((tot[id]=SZ)<=1) return;
 88     MAX=SZ; DFS1(i,0,SZ,id);
 89     vis[ke[id]]=vis[(ke[id]-1^1)+1]=1;
 90     int o[2]={E[ke[id]].to,E[(ke[id]-1^1)+1].to},_sz[2]={sz[o[0]],SZ-sz[o[0]]};
 91     div_tree(o[0],_sz[0],ch[id][0]=++cnt,d+1);
 92     div_tree(o[1],_sz[1],ch[id][1]=++cnt,d+1);
 93     for(int k=0;k<2;k++){
 94         int to=ch[id][k];
 95         l[to]=size[d],rt[d][o[k]]=o[k];
 96         DFS2(o[k],0,d,0);
 97         r[to]=size[d];
 98         if(_sz[k]>1) merge_sort(to,d);
 99         else D[d][l[to]]=(data){o[k],age[o[k]],0};
100         D[d][l[to]].b=dist[d][D[d][l[to]].id];
101         for(int j=l[to]+1;j<r[to];j++)
102             D[d][j].b=dist[d][D[d][j].id]+D[d][j-1].b;
103     }
104     vis[ke[id]]=vis[(ke[id]-1^1)+1]=0;
105 }
106 void solve(int p,int id,int d)
107 {
108     while(tot[id]>1){
109         int x=E[ke[id]].to,y=E[(ke[id]-1^1)+1].to;
110         int dd=rt[d][p]!=x,t=ch[id][dd^1];
111         data tmp;
112         tmp=(data){0,L,0};
113         int ll=lower_bound(D[d]+l[t],D[d]+r[t],tmp,cmp)-D[d]-1;
114         LL v1=ll==l[t]-1?0:D[d][ll].b;
115         tmp=(data){0,R,0};
116         int rr=upper_bound(D[d]+l[t],D[d]+r[t],tmp,cmp)-D[d]-1;
117         LL v2=rr==l[t]-1?0:D[d][rr].b;
118         ans+=v2-v1+(rr-ll)*(E[ke[id]].w+dist[d][p]);
119         id=ch[id][dd],d++;
120     }
121 }
122 void work()
123 {
124     div_tree(1,N,++cnt,1);
125     int u,a,b;
126     for(int i=1;i<=Q;i++){
127         _scanf(u);_scanf(a);_scanf(b);
128         L=min((a+ans)%A,(b+ans)%A);
129         R=max((a+ans)%A,(b+ans)%A);
130         ans=0;
131         solve(u,1,1);
132         _printf(ans),putchar(‘\n‘);
133     }
134 }
135 int main()
136 {
137     data_in();
138     work();
139     return 0;
140 }

原文地址:https://www.cnblogs.com/KKKorange/p/8482370.html

时间: 2024-07-31 22:49:53

BZOJ 4012 HNOI2015 开店 树的边分治的相关文章

BZOJ 4012 HNOI2015 开店 动态树分治+二分

题目大意:给定一棵树,每个点有一个颜色,多次询问颜色在[l,r]区间内的所有点与某个点之间的距离之和,强制在线 没记错的话这题我知道的有三种解法来着? (茴香豆的茴有四种写法泥萌知道嘛-? 1.线段树维护虚树 2.点分治+线段树 3.分块 第一种方法我不知道在线怎么搞= = (我并不知道怎么在虚树上进行点定位 第三种方法貌似内存过不去? 于是果断点分治+线段树 写完发现内存还是炸了= = O(nlog2n)的内存说什么也过不去啊= = 后来发现既然维护的是和不是最值那还要线段树干嘛= = 直接开

[BZOJ 4012][HNOI2015]开店(树链剖分+主席树)

Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面向什么样的人群.很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n个地方,编号为 1 到 n,被 n-1 条带权的边连接起来.每个地方都住着一个妖怪,其中第 i 个地方的妖怪年龄是 x_i.妖怪都是些比较喜欢安静的家伙,所以它们并不希望和很多妖怪相邻.所以这

BZOJ 3672 NOI2014 购票 树的点分治+斜率优化

题目大意:给定一棵以1为根的有根树,每条边有边权,每个点有三个值pi,qi,li 从一个点可以走到它的某个祖先处,前提是距离d不超过li,花销为pi*d+qi 求从每个点到达根节点的最小花销 这道题的上一份题解:http://blog.csdn.net/popoqqq/article/details/39009219 很不幸我作死去重写了一发233 之前的写法真是SB的1B... 为何要暴力- - 明明是分治结构直接排序不行么- - 简述一下做法: 0.先推出斜率优化的动归方程 1.找到当前分治

BZOJ 3365 Distance Statistics 树的点分治

题目大意:同POJ1741 链接:http://blog.csdn.net/popoqqq/article/details/39959803 和POJ1741一样的题,土豪题,POJ有道一样的题,做完1741可以水水 我会告诉你我直接改了下上题的代码么0.0 数据范围4W 距离最大1000 不会爆INT 放心写吧 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm>

[BZOJ4012][HNOI2015]开店(动态点分治)

4012: [HNOI2015]开店 Time Limit: 70 Sec  Memory Limit: 512 MBSubmit: 2168  Solved: 947[Submit][Status][Discuss] Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面 向什么样的人群.很神奇的是,幻想乡的地

bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 &amp;&amp; AC400

3435: [Wc2014]紫荆花之恋 Time Limit: 240 Sec  Memory Limit: 512 MBSubmit: 159  Solved: 40[Submit][Status][Discuss] Description 强 强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上是一个带权树.每个时刻它会长出一个新的叶子节点.每个节点上有一个可爱的小精灵,

bzoj 2152: 聪聪可可 树的点分治

2152: 聪聪可可 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 485  Solved: 251[Submit][Status] Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏.他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

hdu_5314_Happy King(树的点分治)

题目链接:hdu_5314_Happy King 题意: 给出一颗n个结点的树,点上有权值: 求点对(x,y)满足x!=y且x到y的路径上最大值与最小值的差<=D: 题解: 还是树的点分治,在统计答案的时候先按到根的最小值排序,然后用最大值减D去找有多少个满足答案. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 typedef pair<i