bzoj千题计划244:bzoj3730: 震波
http://www.lydsy.com/JudgeOnline/problem.php?id=3730
点分树内对每个节点动态维护2颗线段树
线段树以距离为下标,城市的价值为权值
对于节点x的两棵线段树:
一棵维护 点分树中,x的子树 的贡献
一棵维护 点分树中,x对x的父节点的贡献
查询和修改时,暴力往上爬点分树
点分树保证了最多往上爬log次
查询x k时,先加上点分树内,x的子树中距离<=k的权值和,
再爬到x的父节点f,若x和f的距离为d,则加上f的子树中距离<=k-d的权值和,还要减去 x对f 贡献的<=k-d的权值和,因为这一部分在之前x的子树中算过了
以此类推 ,这就是第二棵线段树的作用
常数优化:
原代码总耗时:20.105 s
#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; #define N 100001 int n,a[N]; int front[N],nxt[N<<],to[N<<],tot; int all,root;
int siz[N],f[N]; bool vis[N]; int dep[N];
int fa[N][],dis[N][]; struct Segment
{
int cnt;
int rt[N];
int lc[N*],rc[N*],val[N*]; void Change(int &k,int l,int r,int x,int y)
{
if(!k) k=++cnt;
if(l==r)
{
val[k]+=y;
return;
}
int mid=l+r>>;
if(x<=mid) Change(lc[k],l,mid,x,y);
else Change(rc[k],mid+,r,x,y);
val[k]=val[lc[k]]+val[rc[k]];
} int Query(int k,int l,int r,int x)
{
if(!k) return ;
if(r<=x) return val[k];
int mid=l+r>>;
if(x<=mid) return Query(lc[k],l,mid,x);
else return val[lc[k]]+Query(rc[k],mid+,r,x);
} }tr,ftr; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} void add(int u,int v)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
} void getroot(int x,int y)
{
siz[x]=; f[x]=;
for(int i=front[x];i;i=nxt[i])
if(to[i]!=y && !vis[to[i]])
{
getroot(to[i],x);
siz[x]+=siz[to[i]];
f[x]=max(f[x],siz[to[i]]);
}
f[x]=max(f[x],all-siz[x]);
if(f[x]<f[root]) root=x;
} void cal(int x,int ancestor,int father,int d)
{
int t;
for(int i=front[x];i;i=nxt[i])
{
t=to[i];
if(t!=father && !vis[t])
{
fa[t][++dep[t]]=ancestor;
dis[t][dep[t]]=d+;
cal(t,ancestor,x,d+);
}
}
} void build(int x)
{
vis[x]=true;
cal(x,x,,);
int tmp=all;
for(int i=front[x];i;i=nxt[i])
if(!vis[to[i]])
{
all=siz[to[i]];
if(all>siz[x]) all=tmp-siz[x];
root=;
getroot(to[i],);
build(root);
}
} void change(int x,int y)
{
tr.Change(tr.rt[x],,n-,,y);
int d;
for(int i=dep[x];i;--i)
{
ftr.Change(ftr.rt[fa[x][i+]],,n-,dis[x][i],y);
// printf("kk %d\n",dis[x][i]);
tr.Change(tr.rt[fa[x][i]],,n-,dis[x][i],y);
}
} int query(int x,int d)
{
int ans=tr.Query(tr.rt[x],,n-,d);
for(int i=dep[x];i;--i)
{
if(d-dis[x][i]>=) ans+=tr.Query(tr.rt[fa[x][i]],,n-,d-dis[x][i]);
if(d-dis[x][i]>=) ans-=ftr.Query(ftr.rt[fa[x][i+]],,n-,d-dis[x][i]);
}
return ans;
} void out(int x)
{
if(x>=) out(x/);
putchar(x%+'');
} int main()
{
freopen("wave.in","r",stdin);
freopen("wave.out","w",stdout);
int size = << ; // 256MB
char *p = (char*)malloc(size) + size;
__asm__("movl %0, %%esp\n" :: "r"(p));
int m;
read(n); read(m);
for(int i=;i<=n;++i) read(a[i]);
int u,v;
for(int i=;i<n;++i)
{
read(u); read(v);
add(u,v);
}
f[]=n+;
all=n;
getroot(,);
build(root);
for(int i=;i<=n;++i) fa[i][dep[i]+]=i;
for(int i=;i<=n;++i)
change(i,a[i]);
int ty,last=;
while(m--)
{
read(ty); read(u); read(v);
u^=last; v^=last;
if(!ty) last=query(u,v),out(last),printf("\n");
else change(u,v-a[u]),a[u]=v;
}
//printf("%d %d",tr.cnt,ftr.cnt);
return ;
}
原代码
1、原本线段树的操作封装在结构体里,拿出来,总耗时:16.934 s
2、动态开节点线段树 单点加:

在寻找x的路径上就进行加操作,而不是找到后再update
总耗时:14.357 s
3、数组改成结构体 总耗时:12.684 s
#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; #define N 100001 int n,a[N]; int front[N],nxt[N<<],to[N<<],tot; int all,root;
int siz[N],f[N]; bool vis[N]; int dep[N];
int fa[N][],dis[N][]; int rt[N<<],cnt; struct node
{
int lc,rc,val;
}tr[N*]; void Change(int &k,int l,int r,int x,int y)
{
if(!k) k=++cnt;
tr[k].val+=y;
if(l==r) return;
int mid=l+r>>;
if(x<=mid) Change(tr[k].lc,l,mid,x,y);
else Change(tr[k].rc,mid+,r,x,y); } int Query(int k,int l,int r,int x)
{
if(!k) return ;
if(r<=x) return tr[k].val;
int mid=l+r>>;
if(x<=mid) return Query(tr[k].lc,l,mid,x);
else return tr[tr[k].lc].val+Query(tr[k].rc,mid+,r,x);
} void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} void add(int u,int v)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
} void getroot(int x,int y)
{
siz[x]=; f[x]=;
for(int i=front[x];i;i=nxt[i])
if(to[i]!=y && !vis[to[i]])
{
getroot(to[i],x);
siz[x]+=siz[to[i]];
f[x]=max(f[x],siz[to[i]]);
}
f[x]=max(f[x],all-siz[x]);
if(f[x]<f[root]) root=x;
} void cal(int x,int ancestor,int father,int d)
{
int t;
for(int i=front[x];i;i=nxt[i])
{
t=to[i];
if(t!=father && !vis[t])
{
fa[t][++dep[t]]=ancestor;
dis[t][dep[t]]=d+;
cal(t,ancestor,x,d+);
}
}
} void build(int x)
{
vis[x]=true;
cal(x,x,,);
int tmp=all;
for(int i=front[x];i;i=nxt[i])
if(!vis[to[i]])
{
all=siz[to[i]];
if(all>siz[x]) all=tmp-siz[x];
root=;
getroot(to[i],);
build(root);
}
} void change(int x,int y)
{
Change(rt[x],,n-,,y);
int d;
for(int i=dep[x];i;--i)
{
Change(rt[fa[x][i+]+n],,n-,dis[x][i],y);
// printf("kk %d\n",dis[x][i]);
Change(rt[fa[x][i]],,n-,dis[x][i],y);
}
} int query(int x,int d)
{
int ans=Query(rt[x],,n-,d);
for(int i=dep[x];i;--i)
{
if(d-dis[x][i]>=) ans+=Query(rt[fa[x][i]],,n-,d-dis[x][i]);
if(d-dis[x][i]>=) ans-=Query(rt[fa[x][i+]+n],,n-,d-dis[x][i]);
}
return ans;
} void out(int x)
{
if(x>=) out(x/);
putchar(x%+'');
} int main()
{
int m;
read(n); read(m);
for(int i=;i<=n;++i) read(a[i]);
int u,v;
for(int i=;i<n;++i)
{
read(u); read(v);
add(u,v);
}
f[]=n+;
all=n;
getroot(,);
build(root);
for(int i=;i<=n;++i) fa[i][dep[i]+]=i;
for(int i=;i<=n;++i)
change(i,a[i]);
int ty,last=;
while(m--)
{
read(ty); read(u); read(v);
u^=last; v^=last;
if(!ty) last=query(u,v),out(last),printf("\n");
else change(u,v-a[u]),a[u]=v;
}
//printf("%d %d",tr.cnt,ftr.cnt);
return ;
}
bzoj千题计划244:bzoj3730: 震波的更多相关文章
- bzoj千题计划300:bzoj4823: [Cqoi2017]老C的方块
http://www.lydsy.com/JudgeOnline/problem.php?id=4823 讨厌的形状就是四联通图 且左右各连一个方块 那么破坏所有满足条件的四联通就好了 按上图方式染色 ...
- bzoj千题计划196:bzoj4826: [Hnoi2017]影魔
http://www.lydsy.com/JudgeOnline/problem.php?id=4826 吐槽一下bzoj这道题的排版是真丑... 我还是粘洛谷的题面吧... 提供p1的攻击力:i,j ...
- bzoj千题计划280:bzoj4592: [Shoi2015]脑洞治疗仪
http://www.lydsy.com/JudgeOnline/problem.php?id=4592 注意操作1 先挖再补,就是补的范围可以包含挖的范围 SHOI2015 的题 略水啊(逃) #i ...
- bzoj千题计划177:bzoj1858: [Scoi2010]序列操作
http://www.lydsy.com/JudgeOnline/problem.php?id=1858 2018 自己写的第1题,一遍过 ^_^ 元旦快乐 #include<cstdio> ...
- bzoj千题计划317:bzoj4650: [Noi2016]优秀的拆分(后缀数组+差分)
https://www.lydsy.com/JudgeOnline/problem.php?id=4650 如果能够预处理出 suf[i] 以i结尾的形式为AA的子串个数 pre[i] 以i开头的形式 ...
- bzoj千题计划304:bzoj3676: [Apio2014]回文串(回文自动机)
https://www.lydsy.com/JudgeOnline/problem.php?id=3676 回文自动机模板题 4年前的APIO如今竟沦为模板,,,╮(╯▽╰)╭,唉 #include& ...
- bzoj千题计划292:bzoj2244: [SDOI2011]拦截导弹
http://www.lydsy.com/JudgeOnline/problem.php?id=2244 每枚导弹成功拦截的概率 = 包含它的最长上升子序列个数/最长上升子序列总个数 pre_len ...
- bzoj千题计划278:bzoj4590: [Shoi2015]自动刷题机
http://www.lydsy.com/JudgeOnline/problem.php?id=4590 二分 这么道水题 没long long WA了两发,没判-1WA了一发,二分写错WA了一发 最 ...
- bzoj千题计划250:bzoj3670: [Noi2014]动物园
http://www.lydsy.com/JudgeOnline/problem.php?id=3670 法一:KMP+st表 抽离nxt数组,构成一棵树 若nxt[i]=j,则i作为j的子节点 那么 ...
随机推荐
- KMP算法 Next数组详解
题面 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百 ...
- 一些比较隐秘的OJ的网址
( 1 )COGS:cogs.pro:8080 ( 2 )AGC:agc012.contest.atcoder.jp ( 3 )CS Acaemy:csacademy.com ( 4 )JoyOI:w ...
- 号称了解mesos双层调度的你,先来回答下面这五个问题!
一提mesos,很多人知道双层调度,但是大多数理解都在表面,不然试一下下面五个问题. 问题一:如果有两个framework,一万个节点,按说应该平均分配给两个framework,怎么个分法?一人一台这 ...
- Firefox扩展安装
firefox扩展和chrome扩展非常相似,甚至兼容.因总结过chrome扩展的开发,这里不提,本篇谈谈firefox扩展的安装. 1.打包 所谓的打包,就是压缩,利用普通的右键压缩文件夹,这样形成 ...
- 创建和注册自定义 HTTP 模块
本演练演示自定义 HTTP 模块的基本功能. 对于每个请求,都需要调用 HTTP 模块以响应 BeginRequest 和 EndRequest 事件. 因此,该模块在处理请求之前和之后运行. 如果 ...
- C语言编程之道--读书笔记
C语言语法 const int nListNum =sizeof(aPrimeList)/sizeof(unsigned);//计算素数表里元素的个数 1:#define INM_MAX 32767 ...
- VS 2017 开发安卓环境搭建 问题总结
VS 2017可以开发安卓啦,之前一直想尝试开发安卓,但是由于时间忙, Java只学了个基础,不如C#熟练所以一直没有机会接触安卓开发.既然需要利用VS2017开发安卓,那么第一步就是了解VS2017 ...
- if语句2017-03-17
1.If语句: if(判断条件){ 判断为true的时候执行的语句 } else{ 判断为false的时候执行的语句 } 2.If else语句: if(判断条件){ 判断为true的时 ...
- redis's usage
author:headsen chen date:2017-12-07 16:33:40 notice:This article is created by headsen chen ,and n ...
- linq使用字符串参数排序
今天找了半天资料,有两种种方法: 1.把字符串参数变为lambda表达式 2.使用System.Linq.dynamic引用 这里我讲第二种方法 第一步:nuget搜索关键字"dynamic ...