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

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

克鲁斯卡尔生成树+倍增?好吧其实有一个更常用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. Vue 加载第三方插件

    如添加jquery. 在终端项目根目录输入命令: npm i -D jquery 等待安装完成 编辑/build/webpack.base.conf.js,在resolve的alias下添加'jque ...

  2. 口碑订单,ERP本地加/退菜无法回流至手机端的解决办法-订单金额不统一erp本地加菜H5没有

    关于 口碑订单,ERP本地加/退菜无法回流至手机端的解决办法-订单金额不统一erp本地加菜H5没有 1. 2. 3. PS:是正餐后付的务必要选择口碑后付 完成以上设置即可

  3. [20190213]测试服务端打开那些端口.txt

    [20190213]测试服务端打开那些端口.txt --//前几天测试使用发送信息到/dev/tcp/ip_address/port,测试端口是否打开.写简单写一个脚本验证看看. $ seq 1 65 ...

  4. [20181108]12c sqlplus rowfetch参数4.txt

    [20181108]12c sqlplus rowfetch参数4.txt --//12cR2 可以改变缺省rowfetch参数.11g之前缺省是1.通过一些测试说明问题.--//前几天做的测试有点乱 ...

  5. Oracle根据已有表的数据建立新表

    需要保证create的表内的字段与select的表一致. create table 表名(字段名,字段名,字段名,字段名,字段名,字段名) as select * from 表名

  6. EOS智能合约授权限制和数据存储

    EOS智能合约授权限制和数据存储 在EOS合约中,调用合约需要来自账户的授权,同时还要指定需要调用的动作.当然,有的合约并不是所有账户都可以调用的,这就需要用到授权限制.接下来我们就来看看如何限制合约 ...

  7. timeout 命令

    命令简介 运行指定的命令,如果在指定时间后仍在运行,则杀死该进程.用来控制程序运行的时间. 使用方法 1 2 3 timeout [选项] 数字[后缀] 命令 [参数]... 后缀 s 代表秒(默认值 ...

  8. c指针类型的作用

    指针类型的作用 任何类型的指针占用的空间大小都是相同的(32位CPU是4字节:64位CPU是8字节) 既然任何类型的指针占用的空间大小都是相同的,为什么指针还需要类型呢?指针只是指向了一个内存地址,但 ...

  9. python模块之sys和subprocess以及编写简单的主机扫描脚本

    python模块之sys和subprocess以及编写简单的主机扫描脚本 1.sys模块 sys.exit(n)  作用:执行到主程序末尾,解释器自动退出,但是如果需要中途退出程序,可以调用sys.e ...

  10. 磁盘测试工具FIO工具安装和使用方法

    一.FIO工具安装: 1.查看fio是否安装 [root@localhost /]#rpm –qa|grep fio 2.源码安装(推荐) 官网地址:http://freecode.com/proje ...