P3206 [HNOI2010] 城市建设
题意
给一张 \(n\) 个点,\(m\) 条边的唔无向图,有边权,\(q\) 次修改,每次修改一条边的边权,查询最小生成树上的边权和。
\(n\le2\times 10^4\),\(m,q\le5\times10^4\)。
思路
把修改边权看作删除原来的边,加入一条新的边。记录每条边出现的时间段,问题变成:给一张图,每次加入/删除一条边,查询最小生成树的边权和。用线段树分治 \(+LCT\) 维护。
时间复杂度 \(\mathcal O(q\log n\log m)\)。
代码
要注意常数,否则容易 \(TLE\)。
// Problem: P3206 [HNOI2010] 城市建设
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3206
// Memory Limit: 500 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
namespace ly{
namespace IO{
#ifndef LOCAL
constexpr auto maxn=1<<20;
char in[maxn],out[maxn],*p1=in,*p2=in,*p3=out;
#define getchar() (p1==p2&&(p2=(p1=in)+fread(in,1,maxn,stdin),p1==p2)?EOF:*p1++)
#define flush() (fwrite(out,1,p3-out,stdout))
#define putchar(x) (p3==out+maxn&&(flush(),p3=out),*p3++=(x))
class Flush{public:~Flush(){flush();}}_;
#endif
namespace usr{
template<typename type>
inline type read(type &x){
x=0;bool flag(0);char ch=getchar();
while(!isdigit(ch)) flag^=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return flag?x=-x:x;
}
template<typename type>
inline void write(type x){
x<0?x=-x,putchar('-'):0;
static short Stack[50],top(0);
do Stack[++top]=x%10,x/=10;while(x);
while(top) putchar(Stack[top--]|48);
}
inline char read(char &x){do x=getchar();while(isspace(x));return x;}
inline char write(const char &x){return putchar(x);}
inline void read(char *x){static char ch;read(ch);do *(x++)=ch;while(!isspace(ch=getchar())&&~ch);}
template<typename type>inline void write(type *x){while(*x)putchar(*(x++));}
inline void read(string &x){static char ch;read(ch),x.clear();do x+=ch;while(!isspace(ch=getchar())&&~ch);}
inline void write(const string &x){for(int i=0,len=x.length();i<len;++i)putchar(x[i]);}
template<typename type,typename...T>inline void read(type &x,T&...y){read(x),read(y...);}
template<typename type,typename...T>
inline void write(const type &x,const T&...y){write(x),putchar(' '),write(y...),sizeof...(y)^1?0:putchar('\n');}
template<typename type>
inline void put(const type &x,bool flag=1){write(x),flag?putchar('\n'):putchar(' ');}
}
#ifndef LOCAL
#undef getchar
#undef flush
#undef putchar
#endif
}using namespace IO::usr;
}using namespace ly::IO::usr;
#define LL long long
const int maxn=50010,maxtime=50010,maxm=100000,maxq=500010;
int n,m,q;
class Link_Cut_Tree{
private:
struct Link_Cut_Tree_node{
int z,ch[2],fa,maxx,max_id;
bool lan;
}t[maxm*16+maxn];
vector<int>path;
inline int get(int u){return t[t[u].fa].ch[1]==u;}
inline bool isroot(int u){return t[t[u].fa].ch[0]!=u&&t[t[u].fa].ch[1]!=u;}
inline void push_up(int u){
t[u].maxx=t[u].z,t[u].max_id=u;
if(t[t[u].ch[0]].maxx>t[u].maxx) t[u].maxx=t[t[u].ch[0]].maxx,t[u].max_id=t[t[u].ch[0]].max_id;
if(t[t[u].ch[1]].maxx>t[u].maxx) t[u].maxx=t[t[u].ch[1]].maxx,t[u].max_id=t[t[u].ch[1]].max_id;
}
inline void rotate(int u){
int fa=t[u].fa,faa=t[fa].fa,d=get(u),dd=get(fa);
t[u].fa=faa;if(!isroot(fa)) t[faa].ch[dd]=u;
t[fa].ch[d]=t[u].ch[!d];if(t[u].ch[!d]) t[t[u].ch[!d]].fa=fa;
t[u].ch[!d]=fa,t[fa].fa=u;
push_up(fa),push_up(u);
}
inline void push_down(int u){
if(t[u].lan==0) return ;
t[u].ch[0]^=t[u].ch[1]^=t[u].ch[0]^=t[u].ch[1];
if(t[u].ch[0]) t[t[u].ch[0]].lan^=1;
if(t[u].ch[1]) t[t[u].ch[1]].lan^=1;
t[u].lan=0;
}
inline void reverse(int u){t[u].lan^=1;push_down(u);}
void push_all(int u){
if(isroot(u)){push_down(u);return ;}
push_all(t[u].fa);
push_down(u);
}
inline int splay(int u){
int v=u;
push_all(u);
for(;!isroot(u);rotate(u)) if(!isroot(t[u].fa)) rotate(get(t[u].fa)==get(u)?t[u].fa:u);return u;
}
inline void access(int u){
int v=0;
while(u) splay(u),t[u].ch[1]=v,push_up(u),u=t[v=u].fa;
}
inline void make_root(int u){access(u),splay(u),reverse(u);}
inline int find_root(int u){
access(u),splay(u);
while(t[u].ch[0]) push_down(u),u=t[u].ch[0];
splay(u);
return u;
}
inline void split(int u,int v){make_root(u),access(v),splay(v);}
inline void new_point(int u,int z){t[u].z=t[u].maxx=z,t[u].max_id=u;}
inline bool is_merged(int u,int v){make_root(u);return find_root(v)==u;}
inline void link(int u,int v){make_root(u);if(find_root(v)!=u) t[u].fa=v;}
inline void cut(int u,int v){split(u,v);t[u].fa=t[v].ch[0]=0;}
public:
friend class Segment_Tree;
};
class Segment_Tree{
private:
Link_Cut_Tree t;
int cnt,top,st1[maxm],st2[maxm],lt[maxm];
LL ans;
struct EDGE{int u,v,w;}b[maxm*16+maxn];
struct Segment_Tree_node{
vector<EDGE>a;
}tr[maxtime*8];
inline void insert(int u,int l,int r,int ll,int rr,EDGE z){
if(l>rr||r<ll) return ;
if(ll<=l&&r<=rr){tr[u].a.push_back(z);return ;}
int mid=l+r>>1;
insert(u<<1,l,mid,ll,rr,z);
insert(u<<1|1,mid+1,r,ll,rr,z);
}
inline void query(int u,int l,int r){
int lt=top;
for(auto x:tr[u].a){
int d=++cnt,u=x.u,v=x.v,w=x.w;
b[d-n]={u,v,w};
t.new_point(d,w);
if(t.is_merged(u,v)){
t.split(u,v);
int id=t.t[v].max_id;
if(t.t[id].z<=w){cnt--;continue;}
t.cut(b[id-n].u,id),t.cut(b[id-n].v,id);
st1[++top]=id;st2[top]=1;
ans-=t.t[id].z;
}
t.link(u,d),t.link(d,v);
st1[++top]=d;st2[top]=0;
ans+=w;
}
if(l==r) write(ans),write('\n');
else{
int mid=l+r>>1;
query(u<<1,l,mid);
query(u<<1|1,mid+1,r);
}
while(top>lt){
int d=st1[top];
int u=b[d-n].u,v=b[d-n].v,w=b[d-n].w;
if(st2[top]) t.link(u,d),t.link(d,v),ans+=w;
else t.cut(u,d),t.cut(d,v),ans-=w;
top--;
}
}
public:
inline void init(){
read(n,m,q);
cnt=n;
for(int i=1;i<=m;i++){
int u,v,w;
read(u,v,w);
b[i]={u,v,w};
}
for(int i=1;i<=q;i++){
int k,d;read(k,d);
insert(1,1,q,lt[k],i-1,b[k]);
b[k].w=d;
lt[k]=i;
}
for(int i=1;i<=m;i++) insert(1,1,q,lt[i],q,b[i]);
}
inline void query(){query(1,1,q);}
}t;
signed main(){
t.init();
t.query();
return 0;
}

浙公网安备 33010602011771号