bzoj 3730 震波 —— 动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3730
建点分树,每个点记两个树状数组,存它作为重心管辖的范围内,所有点到它的距离情况和到它在点分树上的父亲的距离情况;
于是算的时候可以减去重复的,就是跳到父亲之前把自己会被重复统计的部分减去;
注意跳点分树父亲时,查询的距离都是原本询问点到那个父亲的距离,而不是上一层父亲到那个父亲的距离;
树状数组的大小总共是 nlogn 的,因为每层有 n 个点,一共 logn 层;
于是一开始写的是开一个长长的树状数组,记录每个点用的是它上面的哪一段;
然后感觉很艰难...段的长度到底应该是最大深度还是点数?第二个树状数组的段长度是2倍?......
于是改成 vector 了,用 resize() 函数可以方便地开大小,虽然还是不知道具体应该开多大?
查询距离可以把求 LCA 的过程用欧拉序+ST表变成 O(1) 的;
艰难写好,对拍竟然没问题!然而交上去却一直RE...
后来发现前一个操作是修改,并不需要把 ans 赋成0!(对拍没发现是因为不会生成数据,只好每次只做一次查询)
然而还是RE...??
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int const xn=1e5+,xm=xn*,xxn=(xn<<)+;
int n,hd[xn],ct,to[xn<<],nxt[xn<<],v[xn];
int dep[xn],fa[xn],siz[xn],mx,rt,tmp,ans;
//int t[xm],t2[xm<<1],wmx,wmx2,l[xn],r[xn],l2[xn],r2[xn];
int tim,in[xn],st[xxn][],bit[xxn],bin[];
bool vis[xn];
vector<int>tr[xn],tr2[xn];
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return f?ret:-ret;
}
int Max(int x,int y){return x>y?x:y;}
int Min(int x,int y){return x<y?x:y;}
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
void dfsx(int x,int ff)
{
dep[x]=dep[ff]+; in[x]=++tim; st[tim][]=x;
for(int i=hd[x],u;i;i=nxt[i])
if((u=to[i])!=ff)dfsx(u,x),st[++tim][]=x;
//out[x]=++tim; st[tim][0]=x;//
}
void init()
{
dfsx(,);
bin[]=; for(int i=;i<=;i++)bin[i]=bin[i-]*;
bit[]=; for(int i=;i<=tim;i++)bit[i]=bit[i>>]+;
for(int i=;i<=;i++)
for(int j=;j+bin[i-]<=tim&&st[j+bin[i-]][i-];j++)
st[j][i]=Min(st[j][i-],st[j+bin[i-]][i-]);
}
int lca(int x,int y)
{
if(in[x]>in[y])swap(x,y);
int t=bit[in[y]-in[x]+];
return Min(st[in[x]][t],st[in[y]-bin[t]+][t]);
}
int dist(int x,int y){return dep[x]+dep[y]-*dep[lca(x,y)];}
void getrt(int x,int ff,int sum,int dis)
{
int nmx=; siz[x]=;
for(int i=hd[x],u;i;i=nxt[i])
{
if((u=to[i])==ff||vis[u])continue;
getrt(u,x,sum,dis+); siz[x]+=siz[u];
nmx=Max(nmx,siz[u]);
}
nmx=Max(nmx,sum-siz[x]);
if(nmx<mx)mx=nmx,rt=x,tmp=dis;
}
/*
void ins(int nw,int x,int v){if(x==0){t[l[nw]]+=v; return;} for(int p=l[nw]+x;p<=r[nw];x+=(x&-x),p=l[nw]+x)t[p]+=v;}
int query(int nw,int x){int ret=0; for(int p=l[nw]+x;x;x-=(x&-x),p=l[nw]+x)ret+=t[p]; return ret+t[l[nw]];}
void ins2(int nw,int x,int v){
if(x==0){t2[l2[nw]]+=v; return;}
printf("nw=%d x=%d v=%d\n",nw,x,v);
for(int p=l2[nw]+x;p<=r2[nw];x+=(x&-x),p=l2[nw]+x)t2[p]+=v,printf("t2[%d]+=%d x=%d\n",p,v,x);}
int query2(int nw,int x){int ret=0; for(int p=l2[nw]+x;x;x-=(x&-x),p=l2[nw]+x)ret+=t2[p],printf("t2[%d]=%d x=%d\n",p,t2[p],x); return ret+t2[l[nw]];}
*/
void ins(int nw,int x,int v){if(x==){tr[nw][]+=v; return;} for(;x<tr[nw].size();x+=(x&-x))tr[nw][x]+=v;}
int query(int nw,int x){int ret=; x=Min(x,tr[nw].size()-); for(;x;x-=(x&-x))ret+=tr[nw][x]; return ret+tr[nw][];}
void ins2(int nw,int x,int v){if(x==){tr2[nw][]+=v; return;} for(;x<tr2[nw].size();x+=(x&-x))tr2[nw][x]+=v;}
int query2(int nw,int x){int ret=; x=Min(x,tr2[nw].size()-); for(;x;x-=(x&-x))ret+=tr2[nw][x]; return ret+tr2[nw][];}
void dfs(int x,int ff,int dis)
{
ins(rt,dis,v[x]); if(fa[rt])ins2(rt,dist(x,fa[rt]),v[x]);
for(int i=hd[x],u;i;i=nxt[i])
if((u=to[i])!=ff&&!vis[u])dfs(u,x,dis+);
}
void work(int x,int sum)
{
vis[x]=;
ins(x,,v[x]); if(fa[x])ins2(x,dist(x,fa[x]),v[x]);//
for(int i=hd[x],u;i;i=nxt[i])
{
if(vis[u=to[i]])continue;
dfs(u,x,);
}
for(int i=hd[x],u;i;i=nxt[i])
{
if(vis[u=to[i]])continue;
int ns=(siz[u]>siz[x]?sum-siz[x]:siz[u]);
mx=xn; getrt(u,,ns,);
fa[rt]=x;
//len[rt]=tmp;
/*
l[rt]=wmx+1; wmx+=mx+1; r[rt]=wmx;//maxdep
l2[rt]=wmx2+1; wmx2+=2*mx+2; r2[rt]=wmx2;
*/
tr[rt].resize(mx+); tr2[rt].resize(*mx+);
work(rt,ns);
}
}
void ask(int p,int x,int k,int dis)
{
ans+=query(x,k); int len=dist(p,fa[x]);
if(dis>=len&&fa[x])
{
ans-=query2(x,dis-len);
ask(p,fa[x],dis-len,dis);
}
}
void change(int p,int x,int v1,int v2)
{
ins(x,dist(p,x),-v1); ins2(x,dist(p,fa[x]),-v1);
ins(x,dist(p,x),v2); ins2(x,dist(p,fa[x]),v2);
if(fa[x])change(p,fa[x],v1,v2);
}
int main()
{
n=rd(); int m=rd();
for(int i=;i<=n;i++)v[i]=rd();
for(int i=,x,y;i<n;i++)x=rd(),y=rd(),add(x,y),add(y,x);
init();
mx=xn; getrt(,,n,);
/*
l[rt]=wmx+1; wmx+=mx+1; r[rt]=wmx;
l2[rt]=wmx2+1; wmx2+=2*mx+2; r2[rt]=wmx2;
*/
tr[rt].resize(mx+); tr2[rt].resize(*mx+);
work(rt,n);
for(int i=,op,x,y;i<=m;i++)
{
op=rd(); x=(rd()^ans); y=(rd()^ans);
if(op==)ans=,ask(x,x,y,y),printf("%d\n",ans);
else change(x,x,v[x],y),v[x]=y;//,ans=0;
}
return ;
}
RE
然后借鉴了TJ:https://www.cnblogs.com/enigma-aw/p/6209545.html
预处理父亲好方便!
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int const xn=1e5+;
int n,hd[xn],ct,to[xn<<],nxt[xn<<],v[xn];
int dep[xn],siz[xn],mx,rt,ans;
int fa[xn][],dis[xn][];
bool vis[xn];
vector<int>tr[xn],tr2[xn];
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return f?ret:-ret;
}
int Max(int x,int y){return x>y?x:y;}
int Min(int x,int y){return x<y?x:y;}
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
void getrt(int x,int ff,int sum)
{
int nmx=; siz[x]=;
for(int i=hd[x],u;i;i=nxt[i])
{
if((u=to[i])==ff||vis[u])continue;
getrt(u,x,sum); siz[x]+=siz[u];
nmx=Max(nmx,siz[u]);
}
nmx=Max(nmx,sum-siz[x]);
if(nmx<mx)mx=nmx,rt=x;
}
void build(int x,int p,int ff,int d)
{
for(int i=hd[x],u;i;i=nxt[i])
{
if((u=to[i])==ff||vis[u])continue;
fa[u][++dep[u]]=p; dis[u][dep[u]]=d;
build(u,p,x,d+);
}
}
void work(int x,int sum)
{
vis[x]=; build(x,x,,);
tr[x].resize(sum+); tr2[x].resize(sum+);//nlogn
for(int i=hd[x],u;i;i=nxt[i])
{
if(vis[u=to[i]])continue;
int ns=(siz[u]>siz[x]?sum-siz[x]:siz[u]);
mx=xn; getrt(u,,ns); work(rt,ns);
}
}
void ins(int nw,int x,int v){for(;x<tr[nw].size()&&x;x+=(x&-x))tr[nw][x]+=v;}
int query(int nw,int x){if(x<)return ; int ret=; x=Min(x,tr[nw].size()-); for(;x;x-=(x&-x))ret+=tr[nw][x]; return ret+v[nw];}//v[nw]
void ins2(int nw,int x,int v){for(;x<tr2[nw].size()&&x;x+=(x&-x))tr2[nw][x]+=v;}//x
int query2(int nw,int x){if(x<)return ; int ret=; x=Min(x,tr2[nw].size()-); for(;x;x-=(x&-x))ret+=tr2[nw][x]; return ret;}
int ask(int x,int k)
{
int ret=query(x,k);
for(int i=dep[x];i;i--)//
if(k>=dis[x][i])
ret+=query(fa[x][i],k-dis[x][i])-query2(fa[x][i+],k-dis[x][i]);
return ret;
}
void change(int x,int val)
{
int d=dis[x][dep[x]],ff; ins2(x,d,val);//x
for(int i=dep[x];i;i--)
{
d=dis[x][i]; ff=fa[x][i]; ins(ff,d,val);
d=dis[x][i-]; ins2(ff,d,val);//fa[x][i]
}
}
int main()
{
n=rd(); int m=rd();
for(int i=;i<=n;i++)v[i]=rd();
for(int i=,x,y;i<n;i++)x=rd(),y=rd(),add(x,y),add(y,x);
mx=xn; getrt(,,n); work(rt,n);
for(int i=;i<=n;i++)fa[i][dep[i]+]=i;
for(int i=;i<=n;i++)change(i,v[i]);
for(int i=,op,x,y;i<=m;i++)
{
op=rd(); x=(rd()^ans); y=(rd()^ans);
if(op==)ans=ask(x,y),printf("%d\n",ans);
else change(x,y-v[x]),v[x]=y;//,ans=0;
}
return ;
}
bzoj 3730 震波 —— 动态点分治+树状数组的更多相关文章
- bzoj 3730 震波——动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3730 查询一个点可以转化为查询点分树上自己到根的路径上每个点对应范围答案.可用树状数组 f ...
- 【BZOJ-3730】震波 动态点分治 + 树状数组
3730: 震波 Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 626 Solved: 149[Submit][Status][Discuss] D ...
- BZOJ 2683 简单题 cdq分治+树状数组
题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后.二维的数据结构是显然不能过的.于是我们可能会考虑把一维排序之后还有一位上数据结构什么的,然而cdq分治却可以非常好 ...
- bzoj 4372 烁烁的游戏——动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 和 bzoj 3070 震波 是一个套路.注意区间修改的话,树状数组不能表示 dis ...
- bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...
- HDU 4918 Query on the subtree(动态点分治+树状数组)
题意 给定一棵 \(n\) 个节点的树,每个节点有点权.完成 \(q\) 个操作--操作分两种:修改点 \(x\) 的点权.查询与 \(x\) 距离小于等于 \(d\) 的权值总和. \(1 \leq ...
- BZOJ 3648: 寝室管理( 点分治 + 树状数组 )
1棵树的话, 点分治+你喜欢的数据结构(树状数组/线段树/平衡树)就可以秒掉, O(N log^2 N). 假如是环套树, 先去掉环上1条边, 然后O(N log^2 N)处理树(同上); 然后再O( ...
- BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )
考虑cdq分治, 对于[l, r)递归[l, m), [m, r); 然后计算[l, m)的操作对[m, r)中询问的影响就可以了. 具体就是差分答案+排序+离散化然后树状数组维护.操作数为M的话时间 ...
- luogu 5311 [Ynoi2011]D1T3 动态点分治+树状数组
我这份代码已经奇怪到一定程度了~ 洛谷上一直 $TLE$,但是本地造了几个数据都过了. 简单说一下题解: 先建出来点分树. 对于每一个询问,在点分树中尽可能向上跳祖先,看是否能够处理这个询问. 找到最 ...
随机推荐
- iOS开发之获取系统相册ALAssetLibrary
注:当你选择看这篇博客时想必你的应用还支持iOS8一下系统,如果你的应用要求最低版本大于iOS8,建议使用PhotoKit框架,效率更高 ALAssetsLibrary包含,ALAssetsLibra ...
- 基于flask的web微信
web微信 1.扫码获取头像 当你打开web微信的时候,因为http是无状态的,web微信如何实时的获取用户的扫码动作? 那么这里用到的是长轮询的方式. from flask import Flask ...
- C#基础知识之三
C#基础知识之三 1. 程序集间的继承:基类必须被声明为public.必须在project中包含对该基类的程序集引用. 2. 对其它程序集引用和添加对using指令的差别:前者是告诉编译器所需的类 ...
- 如何在ubuntun中安装intellij idea 2018并破解
相比eclipse软件,intellij idea的操作更方便.功能更多,几乎集成了所有的java框架. 安装步骤如下: 1 在https://www.jetbrains.com/idea/网站上下载 ...
- R语言图形base系统(二)
x<-c(1:10) y<-x z<-10/x opar<-par(no.readonly = T) par(mar=c(5,4,4,8)+0.1) plot(x,y,type ...
- PHP-内嵌式语言(转)(未看)
PHP,一个嵌套的缩写名称,是英文超级文本预处理语言(PHP:Hypertext Preprocessor)的缩写.PHP 是一种内嵌式的语言,PHP与微软的ASP颇有几分相似,都是一种在服务器端执行 ...
- img标签中alt属性与title属性
alt属性 1.alt属性是考虑到不支持图像显示或者图像显示被关闭的浏览器的用户,以及视觉障碍的用户和使用屏幕阅读器的用户.当图片不显示的时候,图片的替换文字.2.alt属性值得长度必须少于100个英 ...
- 使用 sqoop 将mysql数据导入到hdfs(import)
Sqoop 将mysql 数据导入到hdfs(import) 1.创建mysql表 CREATE TABLE `sqoop_test` ( `id` ) DEFAULT NULL, `name` va ...
- Spark- 计算每个学科最受欢迎的老师
日志类型 测试数据 http://bigdata.myit.com/zhangsan http://bigdata.myit.com/zhangsan http://bigdata.myit.com/ ...
- idea集成spring+spring MVC+mybatis问题
1.如果mybatis的xml文件放在java文件夹下(idea不会编译src的java目录的xml文件),需要在pom.xml中加入以下代码: <build> <resources ...