题目链接

线段树分治+LCT只有80

然后就有了CDQ分治的做法

把不可能在生成树里的扔到后面

把一定在生成树里的扔到并查集里存起来

分治到l=r,修改边权,跑个kruskal就行了

由于要支持撤销,并查集要按秩合并

#include"cstdio"
#include"cstring"
#include"iostream"
#include"algorithm"
using namespace std; const int MAXN=2e4+5;
const int MAXM=5e4+5;
const int INF=1e9; int n,m,q,t,ct,p;
int f[MAXN],mxdp[MAXN];
long long sum;
long long ans[MAXM];
bool vis[MAXM];
int v[MAXM];
struct rpg{
int ls,nx,ln,id,kd;
}a[MAXM],st[MAXM];
struct vx{
int id,val;
}w[MAXM];
struct fx{
int x,fx,kd;
}stk[MAXM]; int read()
{
int x=0;char ch=getchar();
while(ch<'0'||'9'<ch) ch=getchar();
while('0'<=ch&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
} int find(int x){return f[x]==x?x:find(f[x]);} bool cmp1(rpg a,rpg b){return a.ln<b.ln;}
bool cmp2(rpg a,rpg b){return a.kd<b.kd;}
void un(int fa,int fb)
{
if(mxdp[fa]>mxdp[fb]) swap(fa,fb);
if(mxdp[fa]==mxdp[fb]) stk[++ct]=(fx){fa,fb,1},++mxdp[fb];
else stk[++ct]=(fx){fa,fb,0};
f[fa]=fb;
} long long calc(int d,int t2)
{
for(int i=1;i<=t;++i){
if(a[i].id==w[d].id){
st[w[d].id].ln=a[i].ln=w[d].val;
break;
}
}sort(a+1,a+t+1,cmp1);
long long s=0;
for(int i=1;i<=t;++i){
int fa=find(a[i].ls),fb=find(a[i].nx);
if(fa!=fb) un(fa,fb),s+=a[i].ln;
}while(ct>t2){
if(stk[ct].kd) --mxdp[stk[ct].fx];
f[stk[ct].x]=stk[ct].x;
--ct;
}return sum+s;
} void C(int t2)
{
for(int i=1;i<=t;++i) if(vis[a[i].id]) a[i].ln=INF;
sort(a+1,a+t+1,cmp1);
for(int i=1;i<=t&&a[i].ln<INF;++i){
int fa=find(a[i].ls),fb=find(a[i].nx);
if(fa!=fb) un(fa,fb);
else a[i].kd=2;
}sort(a+1,a+t+1,cmp2);
while(t&&a[t].kd) --t;
while(ct>t2){
if(stk[ct].kd) --mxdp[stk[ct].fx];
f[stk[ct].x]=stk[ct].x;
--ct;
}return;
} void D(int t2)
{
for(int i=1;i<=t;++i) if(vis[a[i].id]) a[i].ln=-INF;
sort(a+1,a+t+1,cmp1);
for(int i=1;i<=t;++i){
int fa=find(a[i].ls),fb=find(a[i].nx);
if(fa!=fb){
un(fa,fb);
if(a[i].ln>-INF) a[i].kd=1,sum+=a[i].ln;
}
}sort(a+1,a+t+1,cmp2);
while(t&&a[t].kd) --t;
while(ct>t2){
if(stk[ct].kd) --mxdp[stk[ct].fx];
f[stk[ct].x]=stk[ct].x;
--ct;
}return;
} void reD(int t2)
{
while(ct>t2){
if(stk[ct].kd) --mxdp[stk[ct].fx];
f[stk[ct].x]=stk[ct].x;
--ct;
}return;
} void reC(int t1)
{
for(int i=t+1;i<=t1;++i){
if(a[i].kd==1) sum-=a[i].ln;
a[i].kd=0;
}t=t1;
return;
} void CDQ(int l,int r)
{
if(l==r){ans[l]=calc(l,ct);return;}
int ctp=t,cmd=ct,mid=l+r>>1;
for(int i=1;i<=t;++i) vis[a[i].id]=0;
for(int i=l;i<=r;++i) vis[w[i].id]=1;
C(cmd),D(cmd);
for(int i=t+1;i<=ctp;++i) if(a[i].kd==1) un(find(a[i].ls),find(a[i].nx));
for(int i=1;i<=t;++i) a[i].ln=st[a[i].id].ln;
CDQ(l,mid),CDQ(mid+1,r);
reC(ctp);reD(cmd);
return;
} int main()
{
n=read(),t=m=read(),q=read();
for(int i=1;i<=n;++i) f[i]=i;
for(int i=1;i<=m;++i) a[i].ls=read(),a[i].nx=read(),a[i].ln=read(),a[i].id=i,st[i]=a[i];
for(int i=1;i<=q;++i) w[i].id=read(),w[i].val=read();
CDQ(1,q);for(int i=1;i<=q;++i) printf("%lld\n",ans[i]);
return 0;
}

【CDQ分治】[HNOI2010]城市建设的更多相关文章

  1. 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)

    [BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...

  2. [HNOI2010]城市建设

    [HNOI2010]城市建设 玄学cdq O(nlog^2n)的动态最小生成树 其实就是按照时间cdq分治+剪枝(剪掉一定出现和不可能出现的边) 处理[l,r]之间的修改以及修改之后的询问,不能确定是 ...

  3. 【LG3206】[HNOI2010]城市建设

    [LG3206][HNOI2010]城市建设 题面 洛谷 题解 有一种又好想.码得又舒服的做法叫线段树分治+\(LCT\) 但是因为常数过大,无法跑过此题. 所以这里主要介绍另外一种玄学\(cdq\) ...

  4. Luogu 3206 [HNOI2010]城市建设

    BZOJ 2001 很神仙的cdq分治 先放论文的链接   顾昱洲_浅谈一类分治算法 我们考虑分治询问,用$solve(l, r)$表示询问编号在$[l, r]$时的情况,那么当$l == r$的时候 ...

  5. 洛谷P3206 [HNOI2010]城市建设

    神仙题 题目大意: 有一张\(n\)个点\(m\)条边的无向联通图,每次修改一条边的边权,问每次修改之后这张图的最小生成树权值和 话说是不是\(cdq\)题目都可以用什么数据结构莽过去啊-- 这道题目 ...

  6. BZOJ2001 HNOI2010城市建设(线段树分治+LCT)

    一个很显然的思路是把边按时间段拆开线段树分治一下,用lct维护MST.理论上复杂度是O((M+Q)logNlogQ),实际常数爆炸T成狗.正解写不动了. #include<iostream> ...

  7. P3206 [HNOI2010]城市建设 [线段树分治+LCT维护动态MST]

    Problem 这题呢 就边权会在某一时刻变掉-众所周知LCT不支持删边的qwq- 所以考虑线段树分治- 直接码一发 如果 R+1 这个时间修改 那就当做 [L,R] 插入了一条边- 然后删的边和加的 ...

  8. BZOJ2001 HNOI2010 城市建设

    题目大意:动态最小生成树,可以离线,每次修改后回答,点数20000,边和修改都是50000. 顾昱洲是真的神:顾昱洲_浅谈一类分治算法 链接: https://pan.baidu.com/s/1c2l ...

  9. [HNOI2010] 城市建设_动态最小生成树(Dynamic_MST)

    这个题...暴力单次修改\(O(n)\),爆炸... $ $ 不过好在可以离线做 如果可以在 分治询问 的时候把图缩小的话就可以做了 硬着头皮把这个骚东西看完了 $ $ 动态最小生成树 然后,就把它当 ...

随机推荐

  1. 提取PPT中的原始图片

    写Word的不如做Excel 的,做Excel不如做PPT的,写代码的不如做PPT. 为了在电子邮件中上传PPT,其中的图片大都经过压缩,以便缩小PPT的体积.那么如何将PPT中的图片,还原成没有经过 ...

  2. (转)面向对象(深入)|python描述器详解

    原文:https://zhuanlan.zhihu.com/p/32764345 https://www.cnblogs.com/aademeng/articles/7262645.html----- ...

  3. idea自己用得到的命令

    1.注释 Ctrl + / 单行注释 . 取消注释 Ctrl + Shift + / 多行注释 .取消注释 2.查找 Ctrl + N 通过输入类名打开类(标准说法是查找类文件) Ctrl + Shi ...

  4. Grape教程-params

    参数 请求参数可以通过params获取,params是一个hash对象,包括GET.POST.PUT参数,以及路径字符串中的任何命名参数: get :public_timeline do Status ...

  5. spring 后处理器

    Bean后处理器 新建maven项目并添加spring依赖,目录结构如下 Axe public interface Axe { public String chop(); } Person publi ...

  6. 站在巨人肩上的.NET Core 2.1

    .NET Core 1.0自发布两年以来,得到了开发者群体相当高地认可. 下图来自Stack overflow survey 2018的统计: .NET Core已经成为前五的主流框架工具,现今借鉴了 ...

  7. 根据js来判断手机是操作系安卓还是ios

    平常开发很常见的功能,在移动端需要根据javaScript来判断手机是安卓还是ios进行应用市场跳转. 通过js提供的Navigator可以来判断手机是安卓还是ios系统,代码如下 1.js判断是否为 ...

  8. 使用ffmpeg实现对h264视频解码 -- (实现了一个易于使用的c++封装库)

    H264是当今流行的视频压缩格式:ffmpeg是一个开源库,实现了对h264视频文件的解压缩. 为了降低使用ffmpeg的复杂性,尽量隐藏实现细节,我写了一个封装库.c#也可以很方便的使用此库.解压后 ...

  9. Ansible中playbook的变量

    转自:http://www.cnblogs.com/lemon-le/p/6862788.html 先看看debug模块的使用: msg:输出调试信息 var:将某个任务执行的输出作为变量传给debu ...

  10. [机器学习] 性能评估指标(精确率、召回率、ROC、AUC)

    混淆矩阵 介绍这些概念之前先来介绍一个概念:混淆矩阵(confusion matrix).对于 k 元分类,其实它就是一个k x k的表格,用来记录分类器的预测结果.对于常见的二元分类,它的混淆矩阵是 ...