题目链接

线段树分治+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. Tomcat 启动成功后报 INFO [Timer-0] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access:

    Tomcat 启动成功后报 INFO [Timer-0] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceL ...

  2. MySQL order by的实现

      1.使用索引的已有顺序 2.filesort算法 filesort算法的执行流程     filesort相关的参数 sort_buffer_size 算法排序缓冲区的大小,线程级缓存 max_l ...

  3. python ftplib模块使用

    Python中默认安装的ftplib模块定义了FTP类,可用来实现简单的ftp客户端,用于上传或下载文件. ftplib模块常用方法 ftp登陆连接 from ftplib import FTP #加 ...

  4. [原创]Chorme密码读取工具\Firefox密码读取工具

    工具: getBrowserPWD编译: VC作者: K8哥哥博客: http://qqhack8.blog.163.com发布: 2017/11/24 16:16:17 简介: 有时为了方便我们会让 ...

  5. 关于AOP的PIAB

    AOP:面向切面编程,也就是在运行过程中,按照需要动态加载功能块 PIAB:含义可以从下面提取 Microsoft Patterns & Practices团队在2007年发布的Enterpr ...

  6. 10-05 Java 内部类概述和讲解

    内部类的概述 /* 内部类概述: 把类定义在其他类的内部,这个类就被称为内部类. 举例:在类A中定义了一个类B,类B就是内部类. 内部的访问特点: A:内部类可以直接访问外部类的成员,包括私有. B: ...

  7. 剑指offer十四之链表中倒数第k个结点

    一.题目 输入一个链表,输出该链表中倒数第k个结点. 二.思路 两个指针,先让第一个指针和第二个指针都指向头结点,然后再让第一个指正走(k-1)步,到达第k个节点.然后两个指针同时往后移动,当第一个结 ...

  8. linux下利用dd命令测试磁盘读写速度

    在Linux中,dd命令用于读取.转换和输出数据,它可从标准输入或文件中读取数据并输出到指定文件或标准输出中.该命令使用参数如下: 其中”=“后面的为设置的参数 If = <文件名>  : ...

  9. 编程珠玑第一章的算法,Java实现,通俗易懂

    该算法也就是所谓的位图算法,用一个int表示32位,也就是实际值为1~32的数. 按照书里说的, 该算法只适合内存有限,而磁盘和时间不限,且数字在1~MAX之间不重复的排序. package demo ...

  10. 堆与堆排序/Heap&Heap sort

    最近在自学算法导论,看到堆排序这一章,来做一下笔记.堆排序是一种时间复杂度为O(lgn)的原址排序算法.它使用了一种叫做堆的数据结构.堆排序具有空间原址性,即指任何时候都需要常数个额外的元素空间存储临 ...