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


给出一个$n$个点的树,树上每一个点都有一个值$age$,每条边都有边权,每次查询一个点,求出树中所有点上权值${L<=age[i]<=R}$的点到它的距离的和。


为了学习传说中的动态树分治,我就把这个题当作模板题来写了。

当然这题也可以树链剖分+权值线段树

  为什么叫做动态树分治?其实就是把分治的结构记录了下来,树分治的好处在于每一次操作(找出当前块重心并再次递归)可以快速减少树的大小,我们记录下这个每次求出的树的重心的结构,这样的分治结构是严格log层的,每一次查询的是沿着分治结构构出的树往上跳,统计所有点到当前点的距离(这里需要数据结构维护,可以开一个vector动态记录每一个点在分治中所管辖的子树的所有点的信息,然后查询的时候二分即可),然后再往分治结构构成的树的父亲上跳,因为在分治结构的父亲所管辖的子树一定包含了当前点所管辖的子树,所以需要容斥(全是细节)。复杂度${O(nlog^{2})}$

  可怕的是BZOJ上似乎卡常?


code:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<ctime>
using namespace std;
#define maxn 600100
#define llg long long
#define RG register llg
#define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
llg Q,A,n,m,age[maxn],ans,dad[maxn],dadv[maxn],maxage,f[maxn][],dis[maxn][],deep[maxn];
bool bj[maxn],bj_[maxn];
llg g[maxn<<],maxl,weizhi,dl[maxn],tail,L,R,o,te,buf[]; inline void write(RG x)
{
if (x<) putchar('-'),x=-x;
buf[]=;
while (x) buf[++buf[]]=x%,x/=;
if (!buf[]) buf[]=,buf[]=;
while (buf[]) putchar(''+buf[buf[]--]);
putchar('\n');
} inline llg getint()
{
llg w=,q=;
char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar();
if (c=='-') q=, c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar();
return q ? -w : w;
} struct edge{
int y,next;
llg d;
}e[maxn<<]; void addedge(RG x,RG y,RG d){
e[++te].y=y;
e[te].d=d;
e[te].next=g[x];
g[x]=te;
} struct node
{
llg age,dis,qz,qz_,dis_;
};
inline bool cmp(const node&a,const node&b) {return a.age<b.age;} vector<node>c[maxn]; inline void clear_() {for (RG i=;i<=tail;i++) bj_[dl[i]]=; tail=;} inline void dfs(RG x,RG fa)
{
for (RG i=g[x];i;i=e[i].next)
{
RG v=e[i].y;
if (v==fa) continue;
f[v][]=x; dis[v][]=e[i].d;
deep[v]=deep[x]+;
dfs(v,x);
}
} inline void make_f()
{
for (RG j=;j<=;j++)
for (RG i=;i<=n;i++)
{
f[i][j]=f[f[i][j-]][j-];
dis[i][j]=dis[i][j-]+dis[f[i][j-]][j-];
}
} inline llg find_dis(RG x,RG y)
{
if (x== || y==) return ;
RG ans=;
if (deep[x]<deep[y]) swap(x,y);
for (RG i=;i>=;i--)
if (deep[f[x][i]]>=deep[y])
{
ans+=dis[x][i];
x=f[x][i];
}
if (x==y) return ans;
for (RG i=;i>=;i--)
if (f[x][i]!=f[y][i])
{
ans+=dis[x][i]+dis[y][i];
x=f[x][i],y=f[y][i];
}
return ans+dis[x][]+dis[y][];
} void init()
{
RG x,y,z;
cin>>n>>Q>>A;
for (RG i=;i<=n;i++) age[i]=getint(),maxage=max(maxage,age[i]);
for (RG i=;i<n;i++)
{
x=getint(),y=getint(),z=getint();
addedge(x,y,z);
addedge(y,x,z);
}
deep[]=;
dfs(,);
make_f();
} inline llg find_size(RG x)
{
bj_[x]=;
dl[++tail]=x;
RG tot=;
for (RG i=g[x];i;i=e[i].next)
{
RG v=e[i].y;
if (bj[v] || bj_[v]) continue;
tot+=find_size(v);
}
return tot;
} inline llg dp(RG x,RG size)
{
bj_[x]=;
dl[++tail]=x;
RG tot=,ma=;
for (register llg i=g[x];i;i=e[i].next)
{
RG v=e[i].y;
if (bj[v] || bj_[v]) continue;
RG he=dp(v,size);
ma=max(ma,he);
tot+=he;
}
ma=max(size-tot,ma);
if (ma<maxl)
{
maxl=ma;
weizhi=x;
}
return tot;
} inline llg find_root(RG x)
{
clear_();
RG size=find_size(x);
clear_();
maxl=n+; weizhi=-;
dp(x,size);
return weizhi;
} inline void dfs_c(RG x,RG now)
{
bj_[x]=; dl[++tail]=x;
node E;
E.age=age[x]; E.dis=find_dis(x,now); E.dis_= find_dis(x,dad[now]);
c[now].push_back(E);
for (RG i=g[x];i;i=e[i].next)
{
RG v=e[i].y;
if (bj[v] || bj_[v]) continue;
dfs_c(v,now);
}
} inline void solve( RG now,RG fa)
{
RG ne=find_root(now);
now=ne;
dadv[now]=find_dis(now,fa);
bj[now]=;
dad[now]=fa;
clear_();
dfs_c(now,now);
for (RG i=g[now];i;i=e[i].next)
{
RG v=e[i].y;
if (bj[v]) continue;
solve(v,now);
}
RG si=c[now].size();
sort(c[now].begin(),c[now].end(),cmp);
c[now][].qz=c[now][].dis;
c[now][].qz_=c[now][].dis_;
for (RG i=;i<si;i++)
{
c[now][i].qz=c[now][i-].qz+c[now][i].dis;
c[now][i].qz_=c[now][i-].qz_+c[now][i].dis_;
}
} void read() {RG x,y; x=getint(),y=getint(); L=min((x+ans)%A,(y+ans)%A); R=max((x+ans)%A,(y+ans)%A);} inline llg erfen(RG x, RG V,RG dis_,bool pd)
{
RG l=,r=c[x].size()-,mid,wz=-;
while (l<=r)
{
mid=(l+r)>>;
if (c[x][mid].age<=V) {wz=mid; l=mid+;}else{r=mid-;}
}
if (wz==-) return ;
if (pd) return c[x][wz].qz+(dis_-find_dis(dad[x],o))*(wz+)-c[x][wz].qz_;
else return c[x][wz].qz_+(wz+)*(find_dis(dad[x],o)-dis_)-c[x][wz].qz;
} inline llg erfen_(RG x,RG V)
{
RG l=,r=c[x].size()-,mid,wz=-;
while (l<=r)
{
mid=(l+r)>>;
if (c[x][mid].age<=V) {wz=mid; l=mid+;}else{r=mid-;}
}
if (wz==-) return ;
return (wz+)*find_dis(dad[x],o)+c[x][wz].qz_;
} inline void find(register llg x)
{
RG dis_=find_dis(x,o);
// llg sum=erfen(x,R,dis_)-erfen(x,L-1,dis_);
// llg dec=erfen_(x,R)-erfen_(x,L-1);
ans+=erfen(x,R,dis_,)+erfen(x,L-,dis_,);
// ans+=sum-dec;
if (dad[x]!=) find(dad[x]);
} llg dg(llg x)
{
if (dad[x]!=) return dg(dad[x])+;
else return ;
} int main()
{
yyj("shop");
init();
solve(,);
/* for (llg i=1;i<=n;i++)
{
maxl=max(maxl,dg(i));
}
cout<<maxl; return 0;*/
while (Q--)
{
o=getint();
read();
ans=;
find(o);
write(ans);
}
// cout<<clock();
return ;
}

【BZOJ】4012: [HNOI2015]开店的更多相关文章

  1. bzoj 4012: [HNOI2015]开店

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  2. bzoj 4012: [HNOI2015]开店 主席树

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  3. BZOJ 4012 HNOI2015 开店 树的边分治+分治树

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4012 题意概述:给出一颗N点的树,保证树上所有点的度不超过3,树上每个点有权值,每条边有权 ...

  4. BZOJ 4012 [HNOI2015]开店 (树分治+二分)

    题目大意: 给你一棵树,边有边权,点有点权,有很多次询问,求点权$\in[l,r]$的所有节点到某点$x$的距离之和,强制在线 感觉这个题应该放在动态点分之前做= = 套路方法和动态点分是一样的 每次 ...

  5. BZOJ 4012 [HNOI2015]开店 (区间修改 永久化标记 主席树)

    讲得好啊 主席树区间修改了,每一次遇到整区间就打永久化标记(不下传,访问的时候沿路径上的标记算答案)然后returnreturnreturn,那么每修改一次只会访问到lognlognlogn个节点,再 ...

  6. [BZOJ4012][HNOI2015]开店(动态点分治,树链剖分)

    4012: [HNOI2015]开店 Time Limit: 70 Sec  Memory Limit: 512 MBSubmit: 2168  Solved: 947[Submit][Status] ...

  7. [HNOI2015]开店 树链剖分,主席树

    [HNOI2015]开店 LG传送门 蒟蒻表示不会动态淀粉质. 先把点按年龄排序, 设\(dis[i]\)表示\(i\)到根的距离. 把我们要算的东西稍微变下形:\(ans\) \[ = \sum \ ...

  8. 洛谷 P3241 [HNOI2015]开店 解题报告

    P3241 [HNOI2015]开店 题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想法当然非 ...

  9. Luogu 3241 [HNOI2015]开店

    BZOJ 4012权限题 浙科协的网突然炸了,好慌…… 据说正解是动态点分治,然而我并不会,我选择树链剖分 + 主席树维护. 设$dis_i$表示$i$到$root(1)$的值,那么对于一个询问$u$ ...

随机推荐

  1. 万恶之源 - Python文件操作

    文件操作 初始文件操作 使用Python来读写文件是非常简单的操作,我们使用open()函数来打开一个文件,获取到文件句柄,然后通过文件句柄就可以进行各种各样的操作了 根据打开方式的不同能够执行的操作 ...

  2. EXTJS 4.2.1.883 Summary 合计栏宽度bug

    EXTJS 4.2.1.883中改进了summary插件,使合计栏能够在grid最底部显示,但是列宽和表格对不上,解决方法: 找到以下样式 .x-docked-summary .x-grid-tabl ...

  3. Linux系统——LNMP分离式部署

    #### 安装nginx ```[root@localhost ~]# tar xf nginx-1.10.2.tar.gz -C /usr/src/[root@localhost ~]# cd /u ...

  4. mysql主从延迟(摘自http://www.linuxidc.com/Linux/2012-02/53995.htm)

    http://www.linuxidc.com/Linux/2012-02/53995.htm

  5. 主成分分析(PCA)学习笔记

    这两天学习了吴恩达老师机器学习中的主成分分析法(Principal Component Analysis, PCA),PCA是一种常用的降维方法.这里对PCA算法做一个小笔记,并利用python完成对 ...

  6. SoapUI 使用变量

    登录问题不好解决, 只能临时用cookie来执行 1.变量定义 2.引用变量 3.调用Header

  7. C++原创应用类库和工具类库

    此博文记载着自编C++应用类库和生成器库的源代码的链接地址,并且对库的开发环境.开发过程.缺陷以及改进更新进行说明. 分数类 利用中午的时间,自己在Visual Studio 2013环境下编写了一个 ...

  8. WindowsServer-性能计数器

    https://jingyan.baidu.com/article/59703552e764e48fc00740dd.html

  9. ImageLoader作用 AAAA

    https://github.com/nostra13/Android-Universal-Image-Loader ImageLoader作用 1.多线程下载图片,图片可以来源于网络,文件系统,项目 ...

  10. PHP进程及进程间通信

    一.引言 进程是一个具有独立功能的程序关于某个数据集合的一次运行活动.换句话说就是,在系统调度多个cpu的时候,一个程序的基本单元.进程对于大多数的语言都不是一个陌生的概念,作为"世界上最好 ...