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+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 震波 —— 动态点分治+树状数组相关推荐
- 【BZOJ-3730】震波 动态点分治 + 树状数组
3730: 震波 Time Limit: 15 Sec Memory Limit: 256 MB Submit: 626 Solved: 149 [Submit][Status][Discuss] ...
- bzoj 3730: 震波 动态点分治+树链剖分+线段树
##### 题目描述 : 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]. 不幸的是,这片土地常常发生地震,并且随 ...
- Bzoj 3730 震波 动态点分治
Bzoj 3730 震波 题解: 和在线的边分治差不多. 就是将每层都信息都存下来. 然后对于每一层记录上一层的重心是哪个. 对于求和的话, 从自己的那层出发,然后暴力往上爬, 然后计算答案. 对于修 ...
- 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 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...
- BZOJ.3648.寝室管理(点分治 树状数组)
BZOJ \(Description\) 求在一棵树上加一条边后,有多少条至少有\(k\)个点的路径. \(n\leq10^5\). \(Solution\) 对于一棵树的情况,可以点分治. 用树状数 ...
- BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )
考虑cdq分治, 对于[l, r)递归[l, m), [m, r); 然后计算[l, m)的操作对[m, r)中询问的影响就可以了. 具体就是差分答案+排序+离散化然后树状数组维护.操作数为M的话时间 ...
- BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化)
BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化) 1 #include<algorithm> 2 #include<iostream> 3 #include ...
- P4093-[HEOI2016/TJOI2016]序列【CDQ分治,树状数组】
正题 题目链接:https://www.luogu.com.cn/problem/P4093 题目大意 nnn个数字,每次有一个数字可能和原序列不同,但最多只有一个不同. 求所有情况下都满足的最长不降 ...
- P3157-[CQOI2011]动态逆序对【CDQ分治,树状数组】
正题 题目链接:https://www.luogu.com.cn/problem/P3157 题目大意 一个长度为nnn序列,每次删除一个数,求删除前的逆序对数量. 解题思路 时光倒流之后,我们变为每 ...
最新文章
- 扩展cocos slider控件,支持禁用置灰
- WMI入门(三):我需要的类在哪里?
- OpenGL创建窗口
- 微信小程序————经纬度转化为具体位置(逆地址解析)
- gunicorn 几种 worker class 性能测试比较
- 二维数组最大子数组和
- 伯克利、OpenAI等提出基于模型的元策略优化强化学习
- HttpInvoker-----客户端实现
- IT职场人生系列之十三:技术?管理?业务?
- 第一天docker入门
- Flex 与.net 进行通信可以通过Fluorine(fluorinefx),WebORB For .net,Socket
- PDA模拟中的问题1
- 投票php实验结果分析与总结,实验的结果分析怎么写
- [三分]求凹凸函数最值
- vc循序渐进实现仿QQ界面(三):界面调色与控件自绘
- Go语言:模拟鼠标操作(go-vgo/robotgo)
- Excel办公常用函数:6大类型,共计64个!
- 亚马逊裁员9000人、OpenAI估值已达290亿美元、首例涉虚拟数字人侵权案
- 白帽子黑客与网络安全工程师带你:远程桌面漏洞利用与Windows7计算机攻防实战
- User32.dll下载+丢失修复