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 ...
随机推荐
- (办公)百度api的使用
这个只是入门,详细的还得看官方的文档http://lbsyun.baidu.com/index.php?title=jspopular3.0/guide/helloworld 百度地图的“Hello, ...
- (其他)window10上好用的软件
1.everything:比我用电脑搜索快一些,(常用的搜索其实熟悉电脑的都会,不过想快一点) 如果你曾对效率工具有过研究,想必对 Everything 的名字不会陌生.这款仅有 1.3 MB 的小软 ...
- java后台打开浏览器代码
import java.awt.Desktop; import java.io.IOException; import java.net.URI; import java.net.URISyntaxE ...
- 使用Visual Studio Team Services敏捷规划和项目组合管理(七)——流程定制
使用Visual Studio Team Services敏捷规划和项目组合管理(七)--流程定制 在Team Services中,可以通过流程定制工作追踪体验.流程定义了工作项跟踪系统的构建部分,以 ...
- Scala隐式转换
package big.data.analyse.scala import java.io.File import scala.io.Source /** * 隐式转换 * Created by zh ...
- python len()函数的用法
函数:len() 返回字符串.列表.字典.元组等长度. 语法:len(str) str:要计算的字符串.列表.字典.元组等 返回值:字符串.列表.字典.元组等元素的长度. Test: 1:计算字符串的 ...
- 区块链会与io域名有什么关系
为什么区块链会与io域名有这么大的联系? 近几年,区块链成为各国央行到国内外各大商业银行.联合国.国际货币基金组织到许多国家政府研究机构讨论的热点,"区块链+"应用创新正在成为引领 ...
- 基于SurfaceView的可拖动视频控件
视频播放控件(一) 可拖动,变换SurfaceView public class DragSurfaceView extends SurfaceView implements View.OnTouch ...
- ELK-logstash-6.3.2-常用配置
1. input-file收集日志信息 [yun@mini04 config]$ pwd /app/logstash/config [yun@mini04 config]$ cat file.conf ...
- SSH 和 Git
了解SSH SSH 以非对称加密实现身份验证.较常用的非对称加密有 RSA. 两种加密过程: 1.通过用户名密码访问服务器,即使传输的数据是加密的也可能会被劫持到不信任的服务器,泄露用户名和密码. 2 ...