这题不错啊,结合了一些不太传统的姿势。

首先看到题目有一问从一个点到另一个点边权最小值。想到了什么?

克鲁斯卡尔生成树+倍增?好吧其实有一个更常用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玩魔塔的更多相关文章

  1. P5168 xtq玩魔塔 [克鲁斯卡尔重构树+带修莫队]

    P5168 xtq玩魔塔 又是码农题- 利用克鲁斯卡尔重构树的性质 我们就可以得出 \(dep\) 值小的,肯定比 \(dep\) 大的值要优. 于是第二问就可以直接 LCA 求出来了- 至于第三问, ...

  2. P5168 xtq玩魔塔

    传送门 其实就是板子--只要会克鲁斯卡尔重构树和带修莫队就可以了 这么想着的我就调了将近一个下午-- 思路其实比较清晰,然而码量很大,细节贼多-- 不难看出只在最小生成树上走最优,于是建出克鲁斯卡尔重 ...

  3. 【Luogu P5168】xtq玩魔塔(Kruskal 重构树 & 树状数组 & set)

    Description 给定一个 \(n\) 个顶点,\(m\) 条边的无向联通图,点.边带权. 先有 \(q\) 次修改或询问,每个指令形如 \(\text{opt}\ x\ y\): \(\tex ...

  4. SDUTOJ2465:其实玩游戏也得学程序(bfs+优先队列+回溯)

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2465 题目描述 由于前两次的打击,ZYJ同学不 ...

  5. 这款打怪升级的小游戏,7 年前出生于 GitHub 社区,如今在谷歌商店有 8 万人打了满分

    今天我在 GitHub 摸鱼寻找新的"目标"时,发现了一个开源项目是 RougeLike 类的角色扮演游戏「破碎版像素地牢」(Shattered Pixel Dungeon)类似魔 ...

  6. Luogu P4705 玩游戏

    题目描述 Alice 和 Bob 又在玩游戏. 对于一次游戏,首先 Alice 获得一个长度为 ​ 的序列 ​,Bob 获得一个长度为 ​ 的序列 bb.之后他们各从自己的序列里随机取出一个数,分别设 ...

  7. Luogu 4705 玩游戏

    看见这个题依稀想起了$5$月月赛时候的事情,到现在仍然它感觉非常神仙. 游戏$k$次价值的期望答案 $$ans_k = \frac{1}{nm}\sum_{i = 1}^{n}\sum_{j = 1} ...

  8. Luogu 4251 [SCOI2015]小凸玩矩阵

    BZOJ 4443 二分答案 + 二分图匹配 外层二分一个最小值,然后检验是否能选出$n - k + 1$个不小于当前二分出的$mid$的数.对于每一个$a_{i, j} \geq mid$,从$i$ ...

  9. [LUOGU] P4251 [SCOI2015]小凸玩矩阵

    行列看成点,格子看成边,二分一个边权,删去大于它的边,新图上的最大流>k则答案可以更优,小于k则调整左边界. #include<algorithm> #include<iost ...

随机推荐

  1. Python 关于类函数设计的一点总结

    关于类函数设计的一点总结 by:授客 QQ:1033553122 代码1 #!/usr/bin/env python #-*-encoding:utf-8-*- __author__ = 'shouk ...

  2. MyEclipse TestNG插件安装与配置

    MyEclipse TestNG插件安装与配置   by:授客 QQ:1033553122 测试环境 jdk1.8.0_121 myeclipse-10.0-offline-installer-win ...

  3. 你不可不知的Java引用类型【总结篇】

    四种引用类型总结 引用级别:强引用 > 软引用 > 弱引用 > 虚引用 理解 就如最开始说的,设置四种引用类型,是为了更好的控制对象的生命周期,让代码能够一定程度上干涉GC过程,所以 ...

  4. 运行svn tortoiseSvn cleanup 命令失败的解决办法

    这个时候请使用命令行模式运行 svn clean up 然后世界和平了:)

  5. (面试题)python面试题集锦-附答案

    1.一行代码实现1-100的和 sum_1_100 = sum(range(1, 101)) 2.如何在一个函数内修改全局变量的值 a = 100 def foo(): global a a = 30 ...

  6. VMware虚拟机安装CentOS系统图文教程

    上一篇:VMware虚拟机安装教程详解图文         上一篇文章给大家介绍了虚拟机的安装,本文为大家详细介绍一下如何在虚拟机安装CentOS系统:   一:VMware虚拟机创建:   1:打开 ...

  7. ERP口碑订单无法落桌的解决方法

    第一步,退出ERP 第二步,打开控制面板卸载erp 第三步,删除erp安装路径的所有文件 第四步,卸载sql服务,操作方法如下(win+R—输入cmd—输入sc delete mysql_sl 回车键 ...

  8. Windows Server 2016-WinSer 2016标准版与数据中心版的区别

    今天在整理文章的时候看到有读者问到他现在的测试环境是用的Windows Server 2016标准版,和我现阶段系列文章的环境是否有区别. 其实针对Windows Server 2016 Active ...

  9. Python描述符的使用

    Python描述符的使用 前言 作为一位python的使用者,你可能使用python有一段时间了,但是对于python中的描述符却未必使用过,接下来是对描述符使用的介绍 场景介绍 为了引入描述符的使用 ...

  10. 如何用Jupyter notebook打开本地数据集

    首先打开本地Jupyter notebook,出现类似页面并进入网页端Home. 网页端界面类似如下: 需要注意的是,Jupyter notebook只能打开当前目录下的数据集,如csv,所以需要使用 ...