题目: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+5,xm=xn*20,xxn=(xn<<1)+5;
int n,hd[xn],ct,to[xn<<1],nxt[xn<<1],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][25],bit[xxn],bin[25];
bool vis[xn];
vector<int>tr[xn],tr2[xn];
int rd()
{int ret=0,f=1; char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',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]+1; in[x]=++tim; st[tim][0]=x;for(int i=hd[x],u;i;i=nxt[i])if((u=to[i])!=ff)dfsx(u,x),st[++tim][0]=x;//out[x]=++tim; st[tim][0]=x;//
}
void init()
{dfsx(1,0);bin[0]=1; for(int i=1;i<=20;i++)bin[i]=bin[i-1]*2;bit[1]=0; for(int i=2;i<=tim;i++)bit[i]=bit[i>>1]+1;for(int i=1;i<=20;i++)for(int j=1;j+bin[i-1]<=tim&&st[j+bin[i-1]][i-1];j++)st[j][i]=Min(st[j][i-1],st[j+bin[i-1]][i-1]);
}
int lca(int x,int y)
{if(in[x]>in[y])swap(x,y);int t=bit[in[y]-in[x]+1];return Min(st[in[x]][t],st[in[y]-bin[t]+1][t]);
}
int dist(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
void getrt(int x,int ff,int sum,int dis)
{int nmx=0; siz[x]=1;for(int i=hd[x],u;i;i=nxt[i]){if((u=to[i])==ff||vis[u])continue;getrt(u,x,sum,dis+1); 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==0){tr[nw][0]+=v; return;} for(;x<tr[nw].size();x+=(x&-x))tr[nw][x]+=v;}
int query(int nw,int x){int ret=0; x=Min(x,tr[nw].size()-1); for(;x;x-=(x&-x))ret+=tr[nw][x]; return ret+tr[nw][0];}
void ins2(int nw,int x,int v){if(x==0){tr2[nw][0]+=v; return;} for(;x<tr2[nw].size();x+=(x&-x))tr2[nw][x]+=v;}
int query2(int nw,int x){int ret=0; x=Min(x,tr2[nw].size()-1); for(;x;x-=(x&-x))ret+=tr2[nw][x]; return ret+tr2[nw][0];}
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+1);
}
void work(int x,int sum)
{vis[x]=1;ins(x,0,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,1);}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,0,ns,1); fa[rt]=x; //len[rt]=tmp; /*l[rt]=wmx+1; wmx+=mx+1; r[rt]=wmx;//maxdepl2[rt]=wmx2+1; wmx2+=2*mx+2; r2[rt]=wmx2;*/tr[rt].resize(mx+1); tr2[rt].resize(2*mx+2);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=1;i<=n;i++)v[i]=rd();for(int i=1,x,y;i<n;i++)x=rd(),y=rd(),add(x,y),add(y,x);init(); mx=xn; getrt(1,0,n,0); /*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+1); tr2[rt].resize(2*mx+2);work(rt,n);for(int i=1,op,x,y;i<=m;i++){op=rd(); x=(rd()^ans); y=(rd()^ans);if(op==0)ans=0,ask(x,x,y,y),printf("%d\n",ans);else change(x,x,v[x],y),v[x]=y;//,ans=0;
    }return 0;
}

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+5;
int n,hd[xn],ct,to[xn<<1],nxt[xn<<1],v[xn];
int dep[xn],siz[xn],mx,rt,ans;
int fa[xn][20],dis[xn][20];
bool vis[xn];
vector<int>tr[xn],tr2[xn];
int rd()
{int ret=0,f=1; char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',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=0; siz[x]=1;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+1);}
}
void work(int x,int sum)
{vis[x]=1; build(x,x,0,1);tr[x].resize(sum+1); tr2[x].resize(sum+1);//nlognfor(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,0,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<0)return 0; int ret=0; x=Min(x,tr[nw].size()-1); 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<0)return 0; int ret=0; x=Min(x,tr2[nw].size()-1); 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+1],k-dis[x][i]);return ret;
}
void change(int x,int val)
{int d=dis[x][dep[x]],ff; ins2(x,d,val);//xfor(int i=dep[x];i;i--){d=dis[x][i]; ff=fa[x][i]; ins(ff,d,val);d=dis[x][i-1]; ins2(ff,d,val);//fa[x][i]
    }
}
int main()
{n=rd(); int m=rd();for(int i=1;i<=n;i++)v[i]=rd();for(int i=1,x,y;i<n;i++)x=rd(),y=rd(),add(x,y),add(y,x);mx=xn; getrt(1,0,n); work(rt,n);for(int i=1;i<=n;i++)fa[i][dep[i]+1]=i;for(int i=1;i<=n;i++)change(i,v[i]);for(int i=1,op,x,y;i<=m;i++){op=rd(); x=(rd()^ans); y=(rd()^ans);if(op==0)ans=ask(x,y),printf("%d\n",ans);else change(x,y-v[x]),v[x]=y;//,ans=0;
    }return 0;
}

转载于:https://www.cnblogs.com/Zinn/p/10185739.html

bzoj 3730 震波 —— 动态点分治+树状数组相关推荐

  1. 【BZOJ-3730】震波 动态点分治 + 树状数组

    3730: 震波 Time Limit: 15 Sec  Memory Limit: 256 MB Submit: 626  Solved: 149 [Submit][Status][Discuss] ...

  2. bzoj 3730: 震波 动态点分治+树链剖分+线段树

    ##### 题目描述 : 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]. 不幸的是,这片土地常常发生地震,并且随 ...

  3. Bzoj 3730 震波 动态点分治

    Bzoj 3730 震波 题解: 和在线的边分治差不多. 就是将每层都信息都存下来. 然后对于每一层记录上一层的重心是哪个. 对于求和的话, 从自己的那层出发,然后暴力往上爬, 然后计算答案. 对于修 ...

  4. bzoj 4372 烁烁的游戏——动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 和 bzoj 3070 震波 是一个套路.注意区间修改的话,树状数组不能表示 dis ...

  5. bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...

  6. BZOJ.3648.寝室管理(点分治 树状数组)

    BZOJ \(Description\) 求在一棵树上加一条边后,有多少条至少有\(k\)个点的路径. \(n\leq10^5\). \(Solution\) 对于一棵树的情况,可以点分治. 用树状数 ...

  7. BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )

    考虑cdq分治, 对于[l, r)递归[l, m), [m, r); 然后计算[l, m)的操作对[m, r)中询问的影响就可以了. 具体就是差分答案+排序+离散化然后树状数组维护.操作数为M的话时间 ...

  8. BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化)

    BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化) 1 #include<algorithm> 2 #include<iostream> 3 #include ...

  9. P4093-[HEOI2016/TJOI2016]序列【CDQ分治,树状数组】

    正题 题目链接:https://www.luogu.com.cn/problem/P4093 题目大意 nnn个数字,每次有一个数字可能和原序列不同,但最多只有一个不同. 求所有情况下都满足的最长不降 ...

  10. P3157-[CQOI2011]动态逆序对【CDQ分治,树状数组】

    正题 题目链接:https://www.luogu.com.cn/problem/P3157 题目大意 一个长度为nnn序列,每次删除一个数,求删除前的逆序对数量. 解题思路 时光倒流之后,我们变为每 ...

最新文章

  1. 扩展cocos slider控件,支持禁用置灰
  2. WMI入门(三):我需要的类在哪里?
  3. OpenGL创建窗口
  4. 微信小程序————经纬度转化为具体位置(逆地址解析)
  5. gunicorn 几种 worker class 性能测试比较
  6. 二维数组最大子数组和
  7. 伯克利、OpenAI等提出基于模型的元策略优化强化学习
  8. HttpInvoker-----客户端实现
  9. IT职场人生系列之十三:技术?管理?业务?
  10. 第一天docker入门
  11. Flex 与.net 进行通信可以通过Fluorine(fluorinefx),WebORB For .net,Socket
  12. PDA模拟中的问题1
  13. 投票php实验结果分析与总结,实验的结果分析怎么写
  14. [三分]求凹凸函数最值
  15. vc循序渐进实现仿QQ界面(三):界面调色与控件自绘
  16. Go语言:模拟鼠标操作(go-vgo/robotgo)
  17. Excel办公常用函数:6大类型,共计64个!
  18. 亚马逊裁员9000人、OpenAI估值已达290亿美元、首例涉虚拟数字人侵权案
  19. 白帽子黑客与网络安全工程师带你:远程桌面漏洞利用与Windows7计算机攻防实战
  20. User32.dll下载+丢失修复

热门文章

  1. 走进Cocos Creator游戏开发(第一篇)
  2. 游戏模型制作的注意事项 项目模型规范总结
  3. 盖茨与鲍尔默愤而诉Google 李开复离职有内情 -- ,买skype来控制桌面建立渠道吧
  4. C++内置类型对象之间的隐式转换
  5. linux 安全删除文件_如何在Linux上安全删除文件
  6. snapchat注册不到_如何将链接添加到您的Snapchat快照
  7. 新胖子公式(java)
  8. 7-2 新胖子公式 (5 分)
  9. 微信小程序(八 配置和请求)
  10. jenkins AWS CodeDeploy不停机部署