Luogu P5168 xtq玩魔塔
这题不错啊,结合了一些不太传统的姿势。
首先看到题目有一问从一个点到另一个点边权最小值。想到了什么?
克鲁斯卡尔生成树+倍增?好吧其实有一个更常用NB的算法叫克鲁斯卡尔重构树
(不会的可以看dalao's blog,并且可以尝试切掉Luogu P4768 [NOI2018]归程)
回到这题,我们可以把重构树建出来之后直接求两点LCA的权值。
然后对于第三问,考虑继续利用重构树,我们发现此时能走到的点在树上一定是一颗子树。
子树内DFS序连续啊,所以就变成区间数颜色了,直接莫队啊!
好吧还有修改,那就带修莫队,在数据随机的情况下稳如老狗。
然后这题就完了,不过有一个细节就是克鲁斯卡尔重构树的父节点权值一定大于子节点,所以不用在向上跳的时候再维护一个最大值数组。
CODE
#include<cstdio>
#include<cctype>
#include<cmath>
#include<algorithm>
#define RI register int
#define Tp template <typename T>
using namespace std;
const int N=100005;
struct data
{
int x,y,val;
inline friend bool operator <(data A,data B)
{
return A.val<B.val;
}
}a[N*3]; int n,m,s,opt,x,y,z,ans[N<<1],rst[N*3],dfn[N<<1],blk[N];
struct ques
{
int l,r,id,t;
inline ques (int L=0,int R=0,int Id=0,int T=0)
{
l=L; r=R; id=Id; t=T;
}
inline friend bool operator <(ques A,ques B)
{
return blk[A.l]!=blk[B.l]?blk[A.l]<blk[B.l]:(blk[A.r]!=blk[B.r]?blk[A.r]<blk[B.r]:A.t<B.t);
}
}q[N<<1]; int cnt_q,cnt_cm,cnt_col,bkt[N*3],tot,d[N<<1],sze[N<<1];
struct operation
{
int pos,col;
inline operation(int Pos=0,int Col=0) { pos=Pos; col=Col; }
}p[N<<1]; int cnt_p,col[N],now,L=1,R,list[N],ret,size;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
public:
Tp inline void read(T &x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
Tp inline void write(T x)
{
if (!x) return (void)(pc('0'),pc('\n')); RI ptop=0;
while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('\n');
}
inline void Fend(void)
{
fwrite(Fout,1,Ftop,stdout);
}
}F;
inline void swap(int &x,int &y)
{
int t=x; x=y; y=t;
}
class Double_Increased_On_Tree
{
private:
static const int P=18;
struct edge
{
int to,nxt;
}e[N<<1]; int head[N<<1],cnt,idx,anc[N<<1][P],dep[N<<1];
inline void reset(int now)
{
for (RI i=0;i<P-1;++i) if (anc[now][i])
anc[now][i+1]=anc[anc[now][i]][i]; else break;
}
inline void miner(int &x,int y)
{
if (y<x) x=y;
}
public:
inline void add(int x,int y)
{
e[++cnt]=(edge){y,head[x]},head[x]=cnt;
}
#define to e[i].to
inline void DFS(int now)
{
if (now<=n) list[dfn[now]=++idx]=now,sze[now]=1;
else dfn[now]=1e9;reset(now); for (RI i=head[now];i;i=e[i].nxt)
anc[to][0]=now,dep[to]=dep[now]+1,DFS(to),sze[now]+=sze[to],miner(dfn[now],dfn[to]);
}
#undef to
inline int getLCA(int x,int y)
{
RI i; if (dep[x]<dep[y]) swap(x,y); for (i=P-1;~i;--i)
if (dep[anc[x][i]]>=dep[y]) x=anc[x][i]; if (x==y) return x;
for (i=P-1;~i;--i) if (anc[x][i]!=anc[y][i])
x=anc[x][i],y=anc[y][i]; return anc[x][0];
}
inline int getinterval(int x,int y)
{
for (RI i=P-1;~i;--i)if (anc[x][i]&&d[anc[x][i]]<=y) x=anc[x][i]; return x;
}
}T;
class Kruskal_Rubuild_Tree_Solver
{
private:
int father[N<<1];
inline int getfather(int x)
{
return father[x]^x?father[x]=getfather(father[x]):x;
}
public:
inline void init(void)
{
for (RI i=1;i<=n;++i) father[i]=i;
}
inline void Kruskal(void)
{
sort(a+1,a+m+1); init(); for (RI i=1;i<=m;++i)
if ((a[i].x=getfather(a[i].x))!=(a[i].y=getfather(a[i].y)))
{
d[++tot]=a[i].val; father[a[i].x]=father[a[i].y]=tot;
T.add(tot,a[i].x); T.add(tot,a[i].y); father[tot]=tot;
}
}
}K;
inline void add(int col)
{
if (++bkt[col]==1) ++ret;
}
inline void del(int col)
{
if (--bkt[col]==0) --ret;
}
inline void travel(int now)
{
if (p[now].pos>=L&&p[now].pos<=R) del(col[list[p[now].pos]]),
add(p[now].col); swap(p[now].col,col[list[p[now].pos]]);
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),F.read(m),F.read(s),i=1;i<=n;++i)
F.read(col[i]),rst[++cnt_col]=col[i]; for (i=1;i<=m;++i)
F.read(a[i].x),F.read(a[i].y),F.read(a[i].val);
for (tot=n,K.Kruskal(),T.DFS(tot),i=1;i<=s;++i)
{
F.read(opt); F.read(x); F.read(y);
switch (opt)
{
case 1:
p[++cnt_p]=operation(dfn[x],y); rst[++cnt_col]=y; break;
case 2:
ans[++cnt_q]=d[T.getLCA(x,y)]; break;
case 3:
int top=T.getinterval(x,y); q[++cnt_cm]=ques(dfn[top],dfn[top]+sze[top]-1,++cnt_q,cnt_p); break;
}
}
sort(rst+1,rst+cnt_col+1); cnt_col=unique(rst+1,rst+cnt_col+1)-rst-1;
for (i=1;i<=n;++i) col[i]=lower_bound(rst+1,rst+cnt_col+1,col[i])-rst;
for (i=1;i<=cnt_p;++i) p[i].col=lower_bound(rst+1,rst+cnt_col+1,p[i].col)-rst;
for (size=(int)pow(n,2.0/3.0),i=1;i<=n;++i) blk[i]=(i-1)/size+1;
for (sort(q+1,q+cnt_cm+1),i=1;i<=cnt_cm;++i)
{
while (now<q[i].t) travel(++now); while (now>q[i].t) travel(now--);
while (L>q[i].l) add(col[list[--L]]); while (R<q[i].r) add(col[list[++R]]);
while (L<q[i].l) del(col[list[L++]]); while (R>q[i].r) del(col[list[R--]]);
ans[q[i].id]=ret;
}
for (i=1;i<=cnt_q;++i) F.write(ans[i]); return F.Fend(),0;
}
Luogu P5168 xtq玩魔塔的更多相关文章
- P5168 xtq玩魔塔 [克鲁斯卡尔重构树+带修莫队]
P5168 xtq玩魔塔 又是码农题- 利用克鲁斯卡尔重构树的性质 我们就可以得出 \(dep\) 值小的,肯定比 \(dep\) 大的值要优. 于是第二问就可以直接 LCA 求出来了- 至于第三问, ...
- P5168 xtq玩魔塔
传送门 其实就是板子--只要会克鲁斯卡尔重构树和带修莫队就可以了 这么想着的我就调了将近一个下午-- 思路其实比较清晰,然而码量很大,细节贼多-- 不难看出只在最小生成树上走最优,于是建出克鲁斯卡尔重 ...
- 【Luogu P5168】xtq玩魔塔(Kruskal 重构树 & 树状数组 & set)
Description 给定一个 \(n\) 个顶点,\(m\) 条边的无向联通图,点.边带权. 先有 \(q\) 次修改或询问,每个指令形如 \(\text{opt}\ x\ y\): \(\tex ...
- SDUTOJ2465:其实玩游戏也得学程序(bfs+优先队列+回溯)
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2465 题目描述 由于前两次的打击,ZYJ同学不 ...
- 这款打怪升级的小游戏,7 年前出生于 GitHub 社区,如今在谷歌商店有 8 万人打了满分
今天我在 GitHub 摸鱼寻找新的"目标"时,发现了一个开源项目是 RougeLike 类的角色扮演游戏「破碎版像素地牢」(Shattered Pixel Dungeon)类似魔 ...
- Luogu P4705 玩游戏
题目描述 Alice 和 Bob 又在玩游戏. 对于一次游戏,首先 Alice 获得一个长度为 的序列 ,Bob 获得一个长度为 的序列 bb.之后他们各从自己的序列里随机取出一个数,分别设 ...
- Luogu 4705 玩游戏
看见这个题依稀想起了$5$月月赛时候的事情,到现在仍然它感觉非常神仙. 游戏$k$次价值的期望答案 $$ans_k = \frac{1}{nm}\sum_{i = 1}^{n}\sum_{j = 1} ...
- Luogu 4251 [SCOI2015]小凸玩矩阵
BZOJ 4443 二分答案 + 二分图匹配 外层二分一个最小值,然后检验是否能选出$n - k + 1$个不小于当前二分出的$mid$的数.对于每一个$a_{i, j} \geq mid$,从$i$ ...
- [LUOGU] P4251 [SCOI2015]小凸玩矩阵
行列看成点,格子看成边,二分一个边权,删去大于它的边,新图上的最大流>k则答案可以更优,小于k则调整左边界. #include<algorithm> #include<iost ...
随机推荐
- 性能测试 CentOS下结合InfluxDB及Grafana图表实时展示JMeter相关性能数据
CentOS下结合InfluxDB及Grafana图表实时展示JMeter相关性能数据 by:授客 QQ:1033553122 实现功能 1 测试环境 1 环境搭建 2 1.安装influxdb ...
- OpenVDB for Mitsuba
https://github.com/zhoub/mitsuba-vdb
- 解决VS2015单元测试“未能设置用于运行测试的执行上下文”问题
VS的单元测试在进行测试时并不像普通Exe会为你提示xx文件未找到,而是类似下面这样: 测试名称: 部署文件到Linux测试全名: unittest::SmartDispatch::部署文件到Linu ...
- 作为IT,你的价值在哪里?
也许最近是真的被无穷无尽的数据整理.导入.再整理.再导入给恶心到了. 业务部提交的数据只是一个非常初始的数据,IT还得在这个基础上七整八整,对导出的结果还要再做二次导入三次导入,不仅要帮业务部批导生成 ...
- realloc 用方法
realloc 用方法 void* realloc(void*, n) 根据n的大小,如果n比较小,就沿用原来的内存地址(也就是返回的地址就是原来的地址),在原来地址的内存空间的最后面,加上n大小的内 ...
- Flask中使用cookie和session
Flask中使用cookie和session 设置cookie from flask import Flask,Response app = Flask(__name__) @app.route('/ ...
- kafka_2.11-2.0.0_安装部署
参考博文:kafka 配置文件参数详解 参考博文:Kafka[第一篇]Kafka集群搭建 参考博文:如何为Kafka集群选择合适的Partitions数量 参考博文:Kafka Server.prop ...
- LeetCode算法题-Remove Linked List Elements(Java实现)
这是悦乐书的第189次更新,第191篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第48题(顺位题号是203).移除单链表中节点值为val的节点.例如: 输入:1-> ...
- KFCM算法的matlab程序(用FCM初始化聚类中心)
KFCM算法的matlab程序(用FCM初始化聚类中心) 在“聚类——KFCM”这篇文章中已经介绍了KFCM算法,现在用matlab程序对iris数据库进行实现,用FCM初始化聚类中心,并求其准确度与 ...
- MATLAB一元线性回归分析
MATLAB一元线性回归分析应用举例 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ huigui.m function [b,bint,r,rint, ...