P8339-[AHOI2022]钥匙【虚树,扫描线】

正题

题目连接:https://www.luogu.com.cn/problem/P8339


题目大意

给出nnn个点的一棵树,每个点有钥匙或者宝箱,有不同的颜色。

mmm次询问,从xxx走到yyy,走到钥匙时会拾取钥匙,走到宝箱时如果有同色的钥匙那么就会消耗一把钥匙打开宝箱,询问能打开多少个宝箱。

保证每一种颜色的钥匙不超过555把。

1≤n≤5×105,1≤m≤1061\leq n\leq 5\times 10^5,1\leq m\leq 10^61n5×105,1m106


解题思路

先考虑同色的宝箱和钥匙都只有一个的情况,这是一个经典问题,假设分别为x,yx,yx,y,那么删去x↔yx\leftrightarrow yxy的路径,xxx的联通块记为SSSyyy的联通块记为TTT

如果询问节点起点在SSS,终点在TTT就会产生贡献。

那么SSSTTT要么两个都是子树,要么一个是子树,另一个是整棵树删去一个子树,也就是说它们都可以表示成dfsdfsdfs序上的一个或两个连续区间。

那么我们把两个区间视为一个二维平面上的正方形+1+1+1,然后询问的视为查询一个点的值,实现方法就是把这些都离线下来用扫描线。

好现在考虑这一题,我们会发现一条路径上我们把单种颜色的拿出来,钥匙视为(((,宝箱视为))),那么就是一个类似括号匹配的东西,每一对产生贡献的点都会满足中间是一个合法的括号序。

那么我们从这个性质入手,我们枚举所有颜色,把同色的点建一棵虚树,对于每个钥匙我们暴力扫全图,能找到很多个合法的贡献对x,yx,yx,y,像上面的方法扫描线就好了。

实际上我们会发现这样枚举出来的贡献对其实是nnn个而不是5n5n5n个的。

时间复杂度:O((n+m)log⁡n)O((n+m)\log n)O((n+m)logn)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
using namespace std;
const int N=5e5+10;
struct node{int to,next;
}a[N<<1];
int n,m,tot,Top,cnt,ls[N],t[N],c[N],s[N],ans[N];
int siz[N],dep[N],son[N],fa[N],top[N],dfn[N],rfn[N],ed[N];
vector<int> G[N],p[N];stack<int> cl;
vector<pair<int,int> >I[N],O[N],q[N];
void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return;
}
bool cmp(int x,int y)
{return rfn[x]<rfn[y];}
void dfs(int x){siz[x]=1;dep[x]=dep[fa[x]]+1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa[x])continue;fa[y]=x;dfs(y);siz[x]+=siz[y];if(siz[y]>siz[son[x]])son[x]=y;}return;
}
void dfs2(int x){dfn[++cnt]=x;rfn[x]=cnt;if(son[x]){top[son[x]]=top[x];dfs2(son[x]);}for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa[x]||y==son[x])continue;top[y]=y;dfs2(y);}ed[x]=cnt;return;
}
int 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;
}
int getTop(int x,int y){while(top[y]!=top[x])if(fa[top[y]]==x)return top[y];else y=fa[top[y]];return dfn[rfn[x]+1];
}
void addG(int x,int y){G[x].push_back(y);G[y].push_back(x);cl.push(x);cl.push(y);return;
}
void Clear(){Top=0;while(!cl.empty()){G[cl.top()].clear();cl.pop();}
}
void Ins(int x){if(!Top){s[++Top]=x;return;}int lca=LCA(s[Top],x);while(Top>1&&dep[s[Top-1]]>=dep[lca])addG(s[Top-1],s[Top]),Top--;if(dep[s[Top]]>dep[lca])addG(lca,s[Top]),Top--;if(s[Top]!=lca)s[++Top]=lca;s[++Top]=x;return;
}
void Build(vector<int> &p){sort(p.begin(),p.end(),cmp);if(p[0]!=1)Ins(1);for(int i=0;i<p.size();i++)Ins(p[i]);while(Top>1)addG(s[Top-1],s[Top]),Top--;
}
void Sets(int x,int y){int lca=LCA(x,y);if(lca==x){x=getTop(x,y);I[1].push_back(mp(rfn[y],ed[y]));O[rfn[x]].push_back(mp(rfn[y],ed[y]));I[ed[x]+1].push_back(mp(rfn[y],ed[y]));}else if(lca==y){y=getTop(y,x);if(rfn[y]>1)I[rfn[x]].push_back(mp(1,rfn[y]-1));if(ed[y]<n)I[rfn[x]].push_back(mp(ed[y]+1,n));if(rfn[y]>1)O[ed[x]+1].push_back(mp(1,rfn[y]-1));if(ed[y]<n)O[ed[x]+1].push_back(mp(ed[y]+1,n));}else{I[rfn[x]].push_back(mp(rfn[y],ed[y]));O[ed[x]+1].push_back(mp(rfn[y],ed[y]));}return;
}
void calc(int x,int fa,int k,int &from,int &_){if(c[x]==-_){k++;}if(c[x]==_){k--;if(!k){Sets(from,x);return;}}for(int i=0;i<G[x].size();i++)if(G[x][i]!=fa)calc(G[x][i],x,k,from,_);
}
void Change(int x,int val){while(x<=n){t[x]+=val;x+=lowbit(x);}return;
}
int Ask(int x){int ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;
}
int main()
{scanf("%d%d",&n,&m);for(int i=1,t;i<=n;i++){scanf("%d%d",&t,&c[i]);p[c[i]].push_back(i);if(t==1)c[i]=-c[i];}for(int i=1,x,y;i<n;i++){scanf("%d%d",&x,&y);addl(x,y);addl(y,x);}dfs(1);dfs2(1);for(int _=1;_<=n;_++){if(p[_].empty())continue;Build(p[_]);for(int i=0;i<p[_].size();i++)if(c[p[_][i]]==-_)calc(p[_][i],0,0,p[_][i],_);Clear();}for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),q[rfn[x]].push_back(mp(rfn[y],i));for(int i=1;i<=n;i++){for(int j=0;j<I[i].size();j++)Change(I[i][j].first,1),Change(I[i][j].second+1,-1);for(int j=0;j<O[i].size();j++)Change(O[i][j].first,-1),Change(O[i][j].second+1,1);for(int j=0;j<q[i].size();j++)ans[q[i][j].second]=Ask(q[i][j].first);}for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);return 0;
}

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

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

相关文章

[HDU 6157]The Karting(DP)

[HDU 6157]The Karting description solution 先用前缀和求出di:1→id_i:1\rightarrow idi​:1→i 的距离 前缀和满足&#xff1a;若在iii点进行方向改变&#xff0c;则iii产生的贡献是一定的&#xff0c;可以先累计贡献 也就是说真正的路径怎么走&#xff0c;我们是不关心…

.NET 开源简史

现在在微软开发开源软件是很一件正常的事情——但在 2007 年&#xff0c;当时我刚加入微软&#xff0c;那时候可不是这么一回事。微软花了好几年时间才找到正确的方向&#xff0c;让微软这艘大船顺着开源之风向前航行。现在回头远望过去那些曾经面临的挑战&#xff0c;我们一笑…

P2617 Dynamic Rankings(整体二分)

P2617 Dynamic Rankings 题意: 待修改的区间最值问题 题解&#xff1a; 整体二分天然带有修改性 整体二分做不带修改的区间最值—>看这里 现在待修改&#xff0c;我们可以将第l位修改为x&#xff0c;因为我们是用树状数组来维护的&#xff0c;所以把这个过程拆分成将第l个…

模板:虚树

所谓虚树&#xff0c;就是虚了的树 &#xff08;逃&#xff09; 前言 在有些时候&#xff0c;我们只关心树上的某些特殊点&#xff0c;问题中的整体规模较大&#xff0c;但是这些特殊点往往比较稀疏&#xff0c;这个时候就可以使用虚树&#xff0c;只保留树上的关键点&#x…

P8340-[AHOI2022]山河重整【dp,倍增】

正题 题目链接:https://www.luogu.com.cn/problem/P8340 题目大意 给出一个nnn和模数PPP。求有多少个在1∼n1\sim n1∼n中选择若干个数的集合SSS&#xff0c;满足1∼n1\sim n1∼n中的每个数都可以表示成SSS的某个子集的和。 1≤n≤5105,2≤P≤1.11091\leq n\leq 5\times 10^5…

[LOJ 6042]「雅礼集训 2017 Day7」跳蚤王国的宰相(树的重心+贪心)

[LOJ 6042]「雅礼集训 2017 Day7」跳蚤王国的宰相 description solution 一个到所有节点距离和最小的节点 ⇔\Leftrightarrow⇔ 树的重心&#xff08;满足最重的儿子最轻&#xff0c;每个儿子siz≤n2\le\frac{n}{2}≤2n​&#xff09; 显然原树的重心答案为0 对于点iii&am…

由优劣语言之争引起的思考

由优劣语言之争引起的思考#欲使其灭亡&#xff0c;必使其疯狂昨天上午由阿里云中间件公众号和架构师小秘圈公众号发布的一篇文章《天天敲代码会使人变聪明么》在.net开发者中掀起了一阵巨浪&#xff0c;文章中提到的语言的先进与落后之争让基于.net开发者们义愤填膺&#xff0c…

P1527 [国家集训队]矩阵乘法

P1527 [国家集训队]矩阵乘法 题意&#xff1a; 给你一个 nn 的矩阵&#xff0c;每次询问一个子矩形的第 k 小数。 题解&#xff1a; 整体二分稍微加强化 模板题是一个序列&#xff0c;现在升级成一个矩阵求&#xff0c;做法和原理都是一样的 使用整体二分解决的题目&#x…

[LOJ #521]「LibreOJ β Round #3」绯色 IOI(抵达)(结论)

#521. 「LibreOJ β Round #3」绯色 IOI&#xff08;抵达&#xff09; description solution 因为点的庇护所不能为自身&#xff0c;题目背景在树上&#xff0c;有结论一定是两个相邻点互为庇护所 所以树一定要能两两完美匹配才有解 判断完有解后就是构造解了&#xff0c;…

UOJ#310-[UNR #2]黎明前的巧克力【FWT】

1# 正题 题目链接:https://uoj.ac/problem/310 题目大意 给出一个长度为nnn的序列&#xff0c;求有多少种方案找出两个集合S,TS,TS,T使得这两个集合的异或和相等。 1≤n≤1061\leq n\leq 10^61≤n≤106 解题思路 可以转换为找到一个异或和为000的集合SSS&#xff0c;产生2∣S…

ybtoj洛谷P4426:毒瘤(虚树,环套树,暴力)

传送门 解析 顾名思义&#xff0c;十分毒瘤 但有一说一&#xff0c;相对来说这题没有之前做的那两个黑题那么&#xff08;重读&#xff09;恶心 而且本题如果放在考场上&#xff0c;暴力枚举非树边的状态dp就可以拿到70分的好成绩&#xff08;改一改能改到75&#xff09; 现…

微软是如何使用 C# 重写 C# 编译器并将其开源的

Roslyn 是 C# 和 Visual Basic.NET 开源编译器的代号。这篇文章将介绍它是如何从微软过去的十年至暗时刻走出来&#xff0c;成为开源跨平台的 C# 和 VB 公共语言引擎。我于 2005 年加入微软&#xff0c;也就是在.NET 2.0 发布之前&#xff0c;当时微软内部已经开始在讨论 Rosly…

P3332 [ZJOI2013]K大数查询(整体二分做法)

P3332 [ZJOI2013]K大数查询 题意: 题解&#xff1a; 利用整体二分来做&#xff0c;这个题和P3834 【模板】可持久化线段树 2的区别在于本题的修改是区间修改&#xff0c;所以将里面的树状数组改成线段树就行&#xff0c;区间修改区间查询 但是不知道为什么我调了一阵子也不对…

[APIO2020]交换城市(交互+kruskal重构树)

[APIO2020]交换城市 description solution 如果u,vu,vu,v存在于一条链上&#xff08;只有两个点度数为111其余点度数为222&#xff09;则无解&#xff0c;否则必有解 如图&#xff0c;不管是哪个点度数>2>2>2&#xff0c;都可以有解 以蓝色为例&#xff0c;第二个…

P3320:寻宝游戏(生成树)

解析 大结论题… 实在是不知道这题和虚树有半毛钱关系吗… 引理 给出一个按照dfs排列的点集S{a1,a2…ak} 它们的极小联通子树的边权和的二倍等于∑dis(a1,a2)dis(a2,a3)...dis(ak−1,ak)dis(ak,a1)\sum dis(a_1,a_2)dis(a_2,a_3)...dis(a_k-1,a_k)dis(a_k,a_1)∑dis(a1​,a2​…

P5333-[JSOI2019]神经网络【dp,容斥】

正题 题目链接:https://www.luogu.com.cn/problem/P5333 题目大意 给出nnn棵树&#xff0c;第iii棵树有kik_iki​个点&#xff0c;每棵树上的每个点和其它树上的所有点都有连边。 求这棵树有多少条哈密顿回路。 答案对998244353998244353998244353取模。 ∑i1nki≤5000\sum…

如何在ASP.NET Core程序启动时运行异步任务(1)

原文&#xff1a;Running async tasks on app startup in ASP.NET Core (Part 1)作者&#xff1a;Andrew Lock译者&#xff1a;Lamond Lu背景当我们做项目的时候&#xff0c;有时候希望自己的ASP.NET Core应用在启动前执行一些初始化逻辑。例如&#xff0c;你希望验证配置是否合…

扫描线讲解

参考文章&#xff1a; 线段树扫描线&#xff08;有关扫描线的理解&#xff09; 线段树扫描线&#xff08;基本原理&#xff09; 扫描线 第二个文章里面的图很生动&#xff1a; 我总结一下就是&#xff1a;将所给图形的横坐标全部记录&#xff0c;纵坐标记录为扫描线 然后对与…

P5400-[CTS2019]随机立方体【二项式反演,计数】

正题 题目链接:https://www.luogu.com.cn/problem/P5400 题目大意 有一个nmln\times m\times lnml的三维网格&#xff0c;要在每个格子处填上一个数&#xff0c;要求填的数中1∼nml1\sim n\times m\times l1∼nml都恰好出现了一次。 一个极大值被定义为这个格子比其他与它至…

「CEOI2019」魔法树(DP+差分启发式合并)

「CEOI2019」魔法树 description solution 设dpi,j:idp_{i,j}:idpi,j​:i子树在jjj时刻的最大果汁量&#xff0c;显然dpi,jdp_{i,j}dpi,j​在jjj是单调递增的 dpi,jmax⁡(dpi,j,dpi,j−1)dp_{i,j}\max(dp_{i,j},dp_{i,j-1})dpi,j​max(dpi,j​,dpi,j−1​) iii不收获 dpi,j∑…