[CF966E] May Holidays(树上数据结构问题、分块+虚树)

Description

一个 n 个结点的有根树,每个结点 x 有一个值 txt_xtx,和一个颜色 (黑/白)。
m 次操作:

  • 翻转某点颜色。
  • 询问有多少点 x 满足:x 为黑色,x 的白色后代数 > tx。
    n, m ≤ 10510^5105

Solution

  • 令 wi = ti− 子树内白点数,那么询问就是 wi < 0 的黑点数,修改就是翻转颜色并将至根路径的w值+1/ − 1。
  • 思来想去好像没有什么奇妙的数据结构能在O(nlogn)O(nlogn)O(nlogn)O(nlog2n)O(nlog^2n)O(nlog2n)内解决这样的问题,于是想到分块。
  • 考虑对询问分块。
  • 使用对询问分块的算法的条件是:
  1. 现在处理的询问块 之前的询问的影响 可以在O(n)O(n)O(n)时间内求出。显然可以满足,处理好每一块的询问后作好标记,处理下一块询问前把整张图再扫一遍即可。
  2. 处理单独一个块内询问的复杂度应该为均摊一次O(B)O(B)O(B)(其中B为块大小)。
  • 对于第二个条件,因为受询问影响的点只有询问点到根的链并,所以先构建块内所有询问点到根的链并,实际上就是一棵虚树,只不过1号点一定要存在在虚树中(因为是链并),显然构建的复杂度是O(BlogB)O(BlogB)O(BlogB)
  • 虚树中同一条边上的点(原树上 处于虚树上相邻两点之间的 那些点),在所有的操作中它们的wi的变化量都是相同的,那么我们可以将它们放到一起处理。
  • 具体来说,对虚树上每条边建一个vector,vector中存处在这条边上的原树上的点,把点按w值排好序,把w值相同的合并到一起,维护一个指针指向最后一个小于0的位置。每次操作后,指针最多平移一位,就可以维护这条边上的点对答案的贡献了。
  • 排序可以用桶排或基数排序优化。
  • 时间复杂度为O(n2B+nB)O(\frac {n^2}B+nB)O(Bn2+nB),显然当B=nB=\sqrt nB=n 时时间复杂度取最优,为O(nn)O(n\sqrt n)O(nn)

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
int read(){int x=0,f=1;char ch=getchar();while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
const int N=100005;
struct Edge{int v,nxt;}edge[N*2];
int n,m,cnt,head[N],t[N],ans[N];
int siz[N],top[N],dep[N],fa[N],ind,dfn[N],mx[N];
int tot,a[N],que[N],stack[N];
bool ins[N],col[N];
//col:颜色
//ins:是否为虚树上点
int b[N*2],c[N],bel[N];
//b[i+n]记录<=i的t值个数
//c[i]表示按t值排序后的第i位
//bel:对于虚树上每个点把它在实树里到虚树父亲的路径上的点全部提出来,标记成它的编号
vector<int> stk,vec[N];
//vec:记录虚树上每个点在实树里到虚树父亲的路径
int p1[N],p2[N];
//p1:vec中的t值(已去重) p2[i]:vec中t值=p1[i]且为白点的点个数 
void addedge(int u,int v){edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt;
}
void dfs1(int x){dep[x]=dep[fa[x]]+1;dfn[x]=++ind;siz[x]=1;for (int i=head[x];i;i=edge[i].nxt)dfs1(edge[i].v),siz[x]+=siz[edge[i].v];mx[x]=ind;
}
void dfs2(int x,int tp){top[x]=tp;int k=0;for(int i=head[x];i;i=edge[i].nxt)if(siz[edge[i].v]>siz[k]) k=edge[i].v;if(k) dfs2(k,tp);for(int i=head[x];i;i=edge[i].nxt)if (edge[i].v!=k) dfs2(edge[i].v,edge[i].v);
}
int get_lca(int x,int y){while (top[x]!=top[y]){if (dep[top[x]]<dep[top[y]]) swap(x,y);x=fa[top[x]];}return dep[x]<dep[y]?x:y;
}
bool cmp(int x,int y){return dfn[x]<dfn[y];
}
void build(){sort(a+1,a+tot+1,cmp);int top=0;stack[++top]=1;stk.push_back(1);for(int i=1;i<=tot;i++){if(a[i]==stack[top]) continue;int lca=get_lca(a[i],stack[top]);if(lca==stack[top]) {stack[++top]=a[i];stk.push_back(a[i]);continue;}while (dep[stack[top-1]]>=dep[lca]) top--;if(dep[stack[top]]>dep[lca]) top--;if(stack[top]!=lca) stack[++top]=lca,stk.push_back(lca);stack[++top]=a[i];stk.push_back(a[i]);}while(top>1) top--;
}void work(int l,int r){for(int i=1;i<=n*2;i++) b[i]=0;for(int i=1;i<=n;i++) b[t[i]+n]++,bel[i]=0;for(int i=1;i<=n*2;i++) b[i]+=b[i-1];for(int i=1;i<=n;i++) c[b[t[i]+n]--]=i;ins[0]=1;for(int i=0;i<stk.size();i++) ins[stk[i]]=1;for(int i=0;i<stk.size();i++)for(int j=fa[stk[i]];!ins[j];j=fa[j])bel[j]=stk[i];int w=0;for(int i=1;i<=n;i++)if(bel[c[i]]) vec[bel[c[i]]].push_back(c[i]);//这样存到vec中就已经按t值排好序了 else w+=(!col[c[i]]&&t[c[i]]<0&&!ins[c[i]]&&!bel[c[i]]);//这波修改是不会对不在虚树边上的点造成影响的 //处理不在虚树边上的点 for(int i=l;i<=r;i++) ans[i]=w;//逐一处理虚树中同一条边上的点 for(int i=0;i<stk.size();i++){int sz=0,x=stk[i];for(int j=0;j<vec[x].size();j++)if(sz&&p1[sz]==t[vec[x][j]]) p2[sz]+=(!col[vec[x][j]]);else p1[++sz]=t[vec[x][j]],p2[sz]=(!col[vec[x][j]]);int pts=0,now=0,tag=0;//now:vec中对答案有贡献的点的个数 while(pts<sz&&p1[pts+1]<0) pts++,now+=p2[pts];for(int j=l;j<=r;j++){col[que[j]]^=1;if(dfn[que[j]]>=dfn[x]&&dfn[que[j]]<=dfn[x]+siz[x]-1){t[x]+=(!col[que[j]])?1:-1;tag+=(!col[que[j]])?1:-1;}while(pts<sz&&p1[pts+1]+tag<0) pts++,now+=p2[pts];while(pts&&p1[pts]+tag>=0) now-=p2[pts],pts--;//两句while分别针对两种情况,一句都不能少 ans[j]+=now;if(t[x]<0&&!col[x]) ans[j]++;}for(int j=l;j<=r;j++) col[que[j]]^=1;//复原 for(int j=0;j<vec[x].size();j++) t[vec[x][j]]+=tag;//更新 }for(int i=l;i<=r;i++) col[que[i]]^=1;//更新 
}
void clear(){for(int i=0;i<stk.size();i++){int x=stk[i];vec[x].clear();ins[x]=0;}stk.clear();
}
int main(){n=read();m=read();for(int i=2;i<=n;i++) fa[i]=read(),addedge(fa[i],i);for(int i=1;i<=n;i++) t[i]=read();for(int i=1;i<=m;i++) que[i]=abs(read());dfs1(1);dfs2(1,1);int B=sqrt(m);for (int i=1;i<=m;i+=B){int tmp=cnt;tot=0;for (int j=0;j<B&&i+j<=m;j++) a[++tot]=que[i+j];//que必须保持输入顺序,只能拿a[]排序建虚树 build();work(i,min(m,i+B-1));cnt=tmp;clear();}for(int i=1;i<=m;i++) printf("%d ",ans[i]);return 0;
}

参考文章:
https://blog.csdn.net/qq_33229466/article/details/80331803
https://blog.csdn.net/Maxwei_wzj/article/details/81950058

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/320256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Asp.Net Core 2.2.0-preview1已经发布

原文地址 ASP.NET Core 2.2.0-preview1 now available今天我们很高兴地宣布,现在可以试用ASP.NET Core和.NET Core的下一个次要版本的第一个预览。在过去的几个月里&#xff0c;我们和社区里的许多人一起为这个版本进行开发&#xff0c;现在它已经准备好让更广泛的受众尝试它并…

YbtOJ#20089-[NOIP2020模拟赛B组Day10]平衡的树【贪心】

正题 题目链接:https://www.ybtoj.com.cn/contest/70/problem/3 题目大意 一棵树nnn个节点&#xff0c;每条边(x,y,a,b)(x,y,a,b)(x,y,a,b)&#xff0c;可以花费111的代价让一条边的a,ba,ba,b都减去111&#xff0c;但是不能小于000&#xff0c;要求最少代价使得每条边满足yyy…

纪中B组模拟赛总结(2020.2.13)

成绩 rankrankranknamenamenamescorescorescoreT1T1T1T2T2T2T3T3T3T4T4T4141414lyflyflyf200200200100100100000000100100100 总结 今天真改“滚”QAQ T1一开始不会&#xff0c;最后才来做&#xff0c;发现了题目的精髓&#xff0c;才切掉 T2打了个ST表&#xff0c;MLE&#x…

牛客网【每日一题】4月28日题目精讲 美味菜肴

链接&#xff1a; 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 32768K&#xff0c;其他语言65536K 64bit IO Format: %lld题目描述 小明是个大厨&#xff0c;早上起来他开始一天的工作。他所在的餐厅每天早上都会买好n件食材&#xff08;每种…

UOJ284 快乐游戏鸡(树上动态规划问题、长链剖分+单调栈)

Description 一棵 n 个点的有根树&#xff0c;带点权 wi。 从 s 出发&#xff0c;希望达到 t&#xff0c;每秒可以从当前点移动到某一个儿子。 有一个死亡次数&#xff0c;初始为 0。若在某个点 i(i ! s, t) 时&#xff0c;死亡次数 ≤ wi&#xff0c;那么死亡次数自增 1&…

C#系列之聊聊.Net Core的InMemoryCache

这两天在看.net core的in memory cache&#xff0c;这里记录一下用法&#xff0c;主要涉及MemoryCache的Get&#xff0f;Set&#xff0f;Expire&#xff0f;Flush。首先我们先用dotnet命令创建一个mvc的项目&#xff0c;这里我们将使用postman来请求server&#xff0c;1dotnet …

P1412-经营与开发【dp】

正题 题目链接:https://www.luogu.com.cn/problem/P1412 题目大意 nnn个地点&#xff0c;有一个能力值为www的稿子 如果地点iii是资源型的&#xff0c;那么可以选择获得ai∗wa_i*wai​∗w的价值&#xff0c;且ww∗(1−k100)ww*(1-\frac{k}{100})ww∗(1−100k​)如果地点iii是…

纪中在家培训总结(2020.2.1~2020.2.24)

前言 因为新型冠状病毒&#xff08;疫情情况&#xff09;的原因&#xff0c;纪中培训改为在家培训&#xff0c;一天的进度变成了两天甚至三天的进度QAQ&#xff0c;但我还是想说&#xff1a;武汉加油&#xff01;中国加油&#xff01; 这次培训总结没啥好写&#xff0c;请勿嘲…

CF1137F Matches Are Not a Child‘s Play(树上数据结构问题、树链剖分+ODT)

Description 一棵 n 个点的树&#xff0c;点权最初为 1 ∼ n 的排列。 定义一个删点过程&#xff1a;每次找到权值最小的叶子&#xff0c;删去它以及连接的边&#xff0c;重复这个过程直到剩下一个点&#xff0c;然后删去最后的点。 处理 q 个询问&#xff1a; 将一个点 x 的…

小石的签到题

链接&#xff1a; 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld题目描述 输入描述: 共一行&#xff0c;输入一个数 n 。 输出描述: 共一行&#xff0c;输出 “Shi” 或 “Yang”&…

值类型、引用类型和泛型的前世今生

值类型、引用类型和泛型多语言咱们先不说主题&#xff0c;先说说CLR支持多语言。 .net有个非常强大的特点&#xff0c;那就是跨语言&#xff0c;支持很多语言&#xff0c;比如C#、J#等。先来个图看一看C# J# VB 等等等

P3247-[HNOI2016]最小公倍数【分块,并查集】

正题 题目链接:https://www.luogu.com.cn/problem/P3247 题目大意 nnn个点mmm条边&#xff0c;每条边有(x,y,a,b)(x,y,a,b)(x,y,a,b)。qqq次询问(x′,y′,a′,b′)(x,y,a,b)(x′,y′,a′,b′)表示询问是否存在一条x′−>y′x->yx′−>y′的路径使得路径上amaxa′,bma…

【DP】奖励卡(jzoj 3937)

奖励卡 jzoj 3937 题目大意 现在有一场比赛&#xff0c;想观看的人要提交申请&#xff0c;现在有x个人提交后得到两个号&#xff0c;y个人提交后得到一个号&#xff0c;有n轮抽号&#xff0c;每一轮抽一个号&#xff08;概率相等&#xff09;&#xff0c;这个号的所有者不参…

CF526G Spiders Evil Plan(树上最优性问题、倍增+线段树)

Description 一棵 n 个结点的树&#xff0c;有正边权。 用 y 条链覆盖这棵树&#xff0c;满足&#xff1a; 所有链连通&#xff08;有重点即算作相连&#xff09;点 x 被覆盖被覆盖的边的权值和尽可能大 q 次给出 x, y&#xff0c;询问最大边权和&#xff0c;强制在线。 n, q…

CAP带你轻松玩转ASP.NETCore消息队列

CAP是什么&#xff1f;CAP是由我们园子里的杨晓东大神开发出来的一套分布式事务的决绝方案&#xff0c;是.Net Core Community中的第一个千星项目&#xff08;目前已经1656 Start&#xff09;&#xff0c;具有轻量级、易使用、高性能等特点。https://github.com/dotnetcore/CAP…

装备合成

链接&#xff1a; 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld题目描述 输入描述: 输入包含t组数据 第一行一个整数t 接下来t行每行两个整数x,y 输出描述: 每组数据输出一行一个…

P4161-[SCOI2009]游戏【dp】

正题 题目链接:https://www.luogu.com.cn/problem/P4161 题目大意 一个1∼n1\sim n1∼n的排列&#xff0c;f(x)f(x)f(x)表示在置换xxx下置换多少次才能回到原来的排列&#xff0c;求在所有置换下f(x)f(x)f(x)的所有可能的值的数量。 解题思路 一个置换的fff值就是这个置换的…

【spfa】假期计划(jzoj 3936)

假期计划 jzoj 3936 题目大意 给你一个有向图&#xff08;n,m⩽20000n,m\leqslant 20000n,m⩽20000&#xff09;&#xff0c;现在有一些作为枢纽的点&#xff0c;且保证每一条边的两个点至少有一个是枢纽点&#xff0c;现在给q个询问&#xff0c;问某一个点到另一个点的最短…

CF650E Clockwork Bomb(树上构造类问题、并查集)

Description 给出两棵 n 结点的有标号树。 每次操作删去第一棵树的一条边&#xff0c;再加上一条边&#xff0c;需要保证此时还是一棵树。 构造一种操作序列&#xff0c;将第一棵树变成第二棵树&#xff0c;使得操作数最小。 n ≤ 51055 \times 10^55105 Solution 显然&…

微软必应从.NET Core 2.1获得了性能提升

据微软工程师Mukul Sabharwal介绍&#xff0c;在将微软搜索引擎必应迁移到.NET Core 2.1之后&#xff0c;内部服务延迟降低了34%&#xff0c;这主要归功于.NET社区贡献的改进。按照Sabharwal的说法&#xff0c;.NET Core的多项改进贡献了大部分的性能提升&#xff0c;包括字符串…