題目大意:給定一張帶權無向圖,每個點有一個顏色,每次改變一個點的顏色,要求你在操作後輸出這個圖中最近異色點對之間的距離
最近異色點對定義爲:一對點顏色不同,且距離最小
老年選手碼什麼數據結構 老老實實退役得了
結論1:答案一定是一條邊的兩端點
證明:假如答案路徑的邊數
結論2:答案邊一定在最小生成樹上
證明:假如答案邊不在最小生成樹上,那麼最小生成樹上兩點之間的路徑上一定能找到一條合法的答案邊,且權值不會比它大
有了這兩個結論其實很好辦了。我們建出最小生成樹,然後每個點開一個以顏色爲下標的線段樹,維護顏色在對應區間的所有子節點離該節點距離的最小值。由於同一顏色的子節點可能有多個,因此要在線段樹的葉節點處開個multiset存該顏色的所有子節點到該節點的距離,以便刪除
然後我們就能統計出每個點到最近異色子節點的距離(異色處理方法:假如顏色爲
具體細節自己YY吧 思路大概就是這樣
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
int n,m,k,q;
int col[M],a[M],fa[M];
int last_ans[M];
multiset<int> ans;
struct Segtree
{
static vector<Segtree*> bin;
union{
Segtree *ls;
multiset<int> *val;
};
Segtree *rs;
int min_x;
void* operator new (size_t)
{
static Segtree *S,*T;
Segtree *re;
if(!bin.empty())
{
re=bin.back();
bin.pop_back();
}
else
{
#define L (1<<16)
if(S==T)
T=(S=new Segtree[L])+L;
re=S++;
}
re->ls=re->rs=0x0;
re->min_x=0x3f3f3f3f;
return re;
}
void operator delete (void *p)
{
bin.push_back((Segtree*)p);
}
void Update()
{
#define MIN(p) ((p)?(p)->min_x:0x3f3f3f3f)
min_x=min(MIN(ls),MIN(rs));
}
friend void Insert(Segtree *&p,int l,int r,int pos,int val)
{
int mid=l+r>>1;
if(!p) p=new Segtree;
if(l==r)
{
if(!p->val)
p->val=new multiset<int>;
p->val->insert(val);
p->min_x=*(p->val->begin());
return ;
}
if(pos<=mid)
Insert(p->ls,l,mid,pos,val);
else
Insert(p->rs,mid+1,r,pos,val);
p->Update();
}
friend void Delete(Segtree *&p,int l,int r,int pos,int val)
{
int mid=l+r>>1;
if(l==r)
{
p->val->erase(p->val->find(val));
if(p->val->empty())
{
delete p->val;
delete p;
p=0x0;
}
else
p->min_x=*(p->val->begin());
return ;
}
if(pos<=mid)
Delete(p->ls,l,mid,pos,val);
else
Delete(p->rs,mid+1,r,pos,val);
p->Update();
if(p->min_x==0x3f3f3f3f)
{
delete p;
p=0x0;
}
}
friend int Query(Segtree *p,int l,int r,int x,int y)
{
int mid=l+r>>1;
if(!p) return 0x3f3f3f3f;
if(x==l&&y==r)
return p->min_x;
if(y<=mid)
return Query(p->ls,l,mid,x,y);
if(x>mid)
return Query(p->rs,mid+1,r,x,y);
return min(Query(p->ls,l,mid,x,mid),Query(p->rs,mid+1,r,mid+1,y));
}
}*root[M];
vector<Segtree*> Segtree::bin;
struct edge
{
int x,y,z;
friend bool operator < (const edge &e1,const edge &e2)
{
return e1.z < e2.z;
}
}edges[M];
struct abcd{
int to,f,next;
}table[M<<1];
int head[M],tot;
void Add(int x,int y,int z)
{
table[++tot].to=y;
table[tot].f=z;
table[tot].next=head[x];
head[x]=tot;
}
namespace Disjoint_Set
{
int fa[M];
int Find(int x)
{
if(!fa[x]||fa[x]==x)
return fa[x]=x;
return fa[x]=Find(fa[x]);
}
void Union(int x,int y)
{
x=Find(x);y=Find(y);
fa[x]=y;
}
}
void Kruskal()
{
using namespace Disjoint_Set;
sort(edges+1,edges+m+1);
for(int i=1;i<=m;i++)
{
int x=Find(edges[i].x);
int y=Find(edges[i].y);
if(x==y)
continue;
Add(edges[i].x,edges[i].y,edges[i].z);
Add(edges[i].y,edges[i].x,edges[i].z);
Union(x,y);
}
}
void BFS()
{
static int q[M];
static bool v[M];
int r=0,h=0;
q[++r]=1;v[1]=true;
while(r!=h)
{
int x=q[++h];
for(int i=head[x];i;i=table[i].next)
if(!v[table[i].to])
{
fa[table[i].to]=x;
a[table[i].to]=table[i].f;
v[table[i].to]=true;
q[++r]=table[i].to;
}
}
}
int Query(int x)
{
int re=0x3f3f3f3f;
if(col[x]!=1)
re=min(re,Query(root[x],1,k,1,col[x]-1));
if(col[x]!=k)
re=min(re,Query(root[x],1,k,col[x]+1,k));
return re;
}
int main()
{
cin>>n>>m>>k>>q;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].z);
Kruskal();
for(int i=1;i<=n;i++)
scanf("%d",&col[i]);
BFS();
for(int i=2;i<=n;i++)
Insert(root[fa[i]],1,k,col[i],a[i]);
for(int i=1;i<=n;i++)
ans.insert(last_ans[i]=Query(i));
for(int i=1,x,y;i<=q;i++)
{
scanf("%d%d",&x,&y);
if(fa[x])
Delete(root[fa[x]],1,k,col[x],a[x]);
col[x]=y;
if(fa[x])
Insert(root[fa[x]],1,k,col[x],a[x]);
ans.erase(ans.find(last_ans[x]));
ans.insert(last_ans[x]=Query(x));
if(fa[x])
{
ans.erase(ans.find(last_ans[fa[x]]));
ans.insert(last_ans[fa[x]]=Query(fa[x]));
}
printf("%d\n",*ans.begin());
}
return 0;
}