给定一张带权无向图,每个点有一个颜色,每次改变一个点的颜色,要求你在操作后输出这个图中最近异色点对之间的距离
最近异色点对定义为:一对点颜色不同,且距离最小
容易想到答案一定在最小生成树上,并且只可能是最小生成树上的某一条边
那么可以对每个节点以颜色为下标建线段树,线段树的叶子节点用multiset记录节点所代表颜色出现的距离,再用一个全局multiset记录全局最小值,就能做到在线修改+查询惹
一开始错是因为对于一条边(x,y,w)而言w被算重了。一个不算重的方法就是每个节点只记录它的儿子,那么每次修改就只需要修改父亲+查询儿子
然后错是因为并不是每个节点都需要用一个multiset,只需要开够叶子节点数量个就行了
接着错是因为可能出现root[x]为0的情况,这样是查询不到东西的
最后错是因为常数巨大,松了松很多次之后才勉强做到9400ms。期间改动的优化包括但不限于:重复利用数组、减少for的数量、记录lastans、输出优化(最不实用
我这么弱也是没有办法(摊手
#include
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int INF=0x3f3f3f3f;
const int N=200005;
const int E=200005;
struct edge {int y,w,next;} e[E*2];
struct rec {int x,y,w;} r[N];
struct treeNode {int l,r,id,min;} t[N*29];
std:: multiset <int> set[N*3],glo;
int root[N],tot;
int ls[N],edCnt,cnt;
int fa[N],a[N],len[N];
int lastans[N];
int n,m,k,T;
bool is_leaf[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch>='0'&&ch<='9';x=(x<<1)+(x<<3)+(ch-'0'),ch=getchar());
return x*v;
}
void writeln(int x){
char ch[21]={}; int i=0;
if (x<0) putchar('-');
do {ch[++i]='0'+x%10;} while (x/=10);
while (i) putchar(ch[i--]);
putchar('\n');
}
void add_edge(int x,int y,int w) {
e[++edCnt]=(edge) {y,w,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,w,ls[y]}; ls[y]=edCnt;
}
int get_father(int x) {
if (fa[x]==x) return x;
return fa[x]=get_father(fa[x]);
}
bool cmp(rec a,rec b) {
return a.wvoid modify(int &now,int tl,int tr,int x,int v,int opt) {
if (!now) t[now=++tot].min=INF;
if (tl==tr) {
if (!t[now].id) t[now].id=++cnt;
int id=t[now].id;
if (opt==0) set[id].erase(set[id].find(v));
else set[id].insert(v);
if (set[id].empty()) t[now].min=INF;
else t[now].min=*(set[id].begin());
return ;
}
int mid=(tl+tr)>>1;
if (x<=mid) modify(t[now].l,tl,mid,x,v,opt);
else modify(t[now].r,mid+1,tr,x,v,opt);
t[now].min=std:: min(t[t[now].l].min,t[t[now].r].min);
}
int query(int now,int tl,int tr,int l,int r) {
if (!now||rreturn INF;
if (tl==l&&tr==r) return t[now].min;
int mid=(tl+tr)>>1;
if (r<=mid) return query(t[now].l,tl,mid,l,r);
if (l>mid) return query(t[now].r,mid+1,tr,l,r);
int qx=query(t[now].l,tl,mid,l,mid);
int qy=query(t[now].r,mid+1,tr,mid+1,r);
return std:: min(qx,qy);
}
void dfs(int now) {
is_leaf[now]=1;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa[now]) continue;
modify(root[now],1,k,a[e[i].y],e[i].w,1);
len[e[i].y]=e[i].w;
fa[e[i].y]=now;
dfs(e[i].y);
is_leaf[now]=0;
}
}
int main(void) { t[0].min=INF;
// freopen("data.in","r",stdin);
// freopen("myp.out","w",stdout);
n=read(),m=read(),k=read(),T=read();
rep(i,1,m) r[i]=(rec) {read(),read(),read()};
rep(i,1,n) fa[i]=i;
std:: sort(r+1,r+m+1,cmp);
int count=0;
rep(i,1,m) {
int fx=get_father(r[i].x);
int fy=get_father(r[i].y);
if (fx!=fy) {
fa[fx]=fy;
add_edge(r[i].x,r[i].y,r[i].w);
if (++count==n-1) break;
}
}
rep(i,1,n) {
a[i]=read();
fa[i]=0;
}
dfs(1);
rep(i,1,n) {
if (is_leaf[i]) continue;
int qx=query(root[i],1,k,1,a[i]-1);
int qy=query(root[i],1,k,a[i]+1,k);
lastans[i]=std:: min(qx,qy);
glo.insert(lastans[i]);
}
for (;T--;) {
int x=read(),v=read();
if (x!=1) {
int up=fa[x];
glo.erase(glo.find(lastans[up]));
modify(root[up],1,k,a[x],len[x],0);
modify(root[up],1,k,v,len[x],1);
int qx=query(root[up],1,k,1,a[up]-1);
int qy=query(root[up],1,k,a[up]+1,k);
lastans[up]=std:: min(qx,qy);
glo.insert(lastans[up]);
}
if (root[x]) {
glo.erase(glo.find(lastans[x]));
int qx=query(root[x],1,k,1,v-1);
int qy=query(root[x],1,k,v+1,k);
lastans[x]=std:: min(qx,qy);
glo.insert(lastans[x]);
}
a[x]=v; int prt=*glo.begin();
writeln(prt);
}
return 0;
}