这题可真TM调的我一逼。。校内测试时用sort水了60正解需要知道两个性质。。
性质1:最后解一定是一条边。因为如果有3个点A,B,C且A,C通过B相连,且A,C,颜色不同,那么B和A,C中一个点颜色一定不同(显然)然而w(A,C)>w(B,C)||w(A,B)
性质2:最后解一定在最小生成树里
假如答案边不在最小生成树上,那么最小生成树上两点之间的路径上一定能找到一条合法的答案边,且权值不会比它大
有了性质后就可以先Kruskal最小生成树然后再对每一个节点建树套树或树套set
再维护一个Ans的平衡树或set
还有这题zz到卡内存到丧心病狂。。自行体会一下吧。
树套树:
#define MAXN 205005 #define inf (0x3f3f3f3f) #include <iostream> #include <queue> #include <cstring> #include <stdio.h> #include <vector> #include <algorithm> using namespace std; int first[MAXN],e=1,n,m,k,q,val[MAXN],cost[MAXN],f[MAXN],last[MAXN]; template<typename _t> inline _t read(){ _t x=0; int f=1; char ch=getchar(); for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f; for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+ch-48; return (_t)x*f; } struct edge{ int u,v,next,w; bool operator < (const edge &a)const{ return w<a.w; } }a[MAXN<<1],b[MAXN<<1]; void push(int u,int v,int w){ a[e].u=u; a[e].v=v; a[e].w=w; a[e].next=first[u]; first[u]=e++; } int fa[MAXN]; int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void Bfs(){ bool vis[MAXN]; memset(vis,0,sizeof vis); queue<int>q; q.push(1); vis[1]=1; while(!q.empty()){ int k = q.front(); q.pop(); for(int i=first[k];i;i=a[i].next){ if(!vis[a[i].v]){ f[a[i].v]=k; cost[a[i].v]=a[i].w; vis[a[i].v]=1; q.push(a[i].v); } } } } void Kr(){ sort(b+1,b+1+m); int cnt = 0; for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=m;i++){ int u = find(b[i].u),v=find(b[i].v); if(u==v)continue; fa[u]=v; push(b[i].u,b[i].v,b[i].w); push(b[i].v,b[i].u,b[i].w); if(cnt==n-1)break; } Bfs(); } struct Treap_node{ int v,r; Treap_node *ch[2]; Treap_node(){} Treap_node(int x){ v = x;r=rand(); ch[0]=ch[1]=NULL; } void *operator new (size_t); void operator delete (void* p); int cmp(int x)const{ if(x==v)return -1; return x<v?0:1; } }*C,*mempool,*Ans; vector<Treap_node*>Stack; void* Treap_node :: operator new (size_t){ Treap_node *p; if(!Stack.empty()){ p = Stack.back(); Stack.pop_back(); } else{ if(C==mempool){ C=new Treap_node[1<<15]; mempool = C+(1<<15); } p=C++; } return p; } void Treap_node :: operator delete (void* p){ Stack.push_back((Treap_node*)p); } void rotate (Treap_node *&o,int d){ Treap_node *p=o->ch[d^1]; o->ch[d^1]=p->ch[d]; p->ch[d]=o; o=p; } void Treap_insert(Treap_node *&o,int x){ if(!o)o=new Treap_node(x); else{ int d = x<o->v ? 0:1; Treap_insert(o->ch[d],x); if(o->ch[d]->r > o->r)rotate(o,d^1); } } void Treap_erase(Treap_node *&o,int x){ int d = o->cmp(x); if(d==-1){ Treap_node *tmp = o; if(o->ch[0]!=NULL&&o->ch[1]!=NULL){ int k = o->ch[0]->r > o->ch[1]->r ? 1:0; rotate(o,k); Treap_erase(o->ch[k],x); } else{ if(o->ch[1]==NULL)o=o->ch[0]; else o = o->ch[1]; delete tmp; tmp = NULL; } } else Treap_erase(o->ch[d],x); } int Treap_Query(Treap_node *x){ int tot = inf; while(x){ tot=min(tot,x->v); x=x->ch[0]; } return tot; } struct Tree{ Tree *ls,*rs; Treap_node *v; int min_x; Tree() { ls=rs=NULL,v=NULL,min_x=inf; } void Push_up(){ #define MIN(x) ((x)?((x)->min_x):inf) min_x=min(MIN(ls),MIN(rs)); } void* operator new (size_t); void operator delete(void* p); }*root[MAXN],*S,*T; vector<Tree*>bin; void* Tree :: operator new(size_t size){ Tree *o; if(!bin.empty()){ o=bin.back(); bin.pop_back(); } else{ if(S==T){ S=new Tree[1<<15]; T=S+(1<<15); } o = S++; } o->ls=o->rs=NULL; o->v=NULL; o->min_x=inf; return o; } void Tree :: operator delete (void* p){ bin.push_back((Tree*)p); } void insert(Tree *&o,int l,int r,int x,int va){ if(!o)o = new Tree; if(l==r){ Treap_insert(o->v,va); o->min_x=Treap_Query(o->v); return; } int mid=l+r>>1; if(x<=mid)insert(o->ls,l,mid,x,va); else insert(o->rs,mid+1,r,x,va); o->Push_up(); } void erase(Tree *&o,int l,int r,int x,int va){ if(l==r){ Treap_erase(o->v,va); o->min_x=Treap_Query(o->v); return; } int mid = l+r>> 1; if(x<=mid)erase(o->ls,l,mid,x,va); else erase(o->rs,mid+1,r,x,va); o->Push_up(); if(o->min_x==inf){ delete o; o=NULL; } } int query(Tree *o,int l,int r,int x,int y){ if(!o)return inf; if(x<=l&&r<=y)return o->min_x; int mid = l+r>>1,ans=inf; if(x<=mid)ans=min(ans,query(o->ls,l,mid,x,y)); if(mid<y)ans=min(ans,query(o->rs,mid+1,r,x,y)); return ans; } int Query(int x){ int ans = inf; if(val[x]!=1)ans=min(ans,query(root[x],1,k,1,val[x]-1)); if(val[x]!=k)ans=min(ans,query(root[x],1,k,val[x]+1,k)); return ans; } int main(){ bin.clear(); n=read<int>(); m=read<int>(); k=read<int>(); q=read<int>(); for(int i=1;i<=m;i++)scanf("%d%d%d",&b[i].u,&b[i].v,&b[i].w); for(int i=1;i<=n;i++)scanf("%d",&val[i]);Kr(); for(int i=2;i<=n;i++)insert(root[f[i]],1,k,val[i],cost[i]); for(int i=1;i<=n;i++)Treap_insert(Ans,last[i]=Query(i)); while(q--){ int pos=read<int>(),w=read<int>(); if(f[pos])erase(root[f[pos]],1,k,val[pos],cost[pos]); val[pos]=w; if(f[pos])insert(root[f[pos]],1,k,val[pos],cost[pos]); Treap_erase(Ans,last[pos]); Treap_insert(Ans,last[pos]=Query(pos)); if(f[pos]){ Treap_erase(Ans,last[f[pos]]); Treap_insert(Ans,last[f[pos]]=Query(f[pos])); } printf("%d\n",Treap_Query(Ans)); } }树+Set#define MAXN 205005 #define inf (0x3f3f3f3f) #include <iostream> #include <set> #include <queue> #include <cstring> #include <stdio.h> #include <vector> #include <algorithm> using namespace std; int first[MAXN],e=1,n,m,k,q,val[MAXN],cost[MAXN],f[MAXN],last[MAXN]; multiset<int>Ans; multiset<int>::iterator it; template<typename _t> inline _t read(){ _t x=0; int f=1; char ch=getchar(); for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f; for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+ch-48; return (_t)x*f; } struct edge{ int u,v,next,w; bool operator < (const edge &a)const{ return w<a.w; } }a[MAXN<<1],b[MAXN<<1]; void push(int u,int v,int w){ a[e].u=u; a[e].v=v; a[e].w=w; a[e].next=first[u]; first[u]=e++; } int fa[MAXN]; int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void Bfs(){ bool vis[MAXN]; memset(vis,0,sizeof vis); queue<int>q; q.push(1); vis[1]=1; while(!q.empty()){ int k = q.front(); q.pop(); for(int i=first[k];i;i=a[i].next){ if(!vis[a[i].v]){ f[a[i].v]=k; cost[a[i].v]=a[i].w; vis[a[i].v]=1; q.push(a[i].v); } } } } void Kr(){ sort(b+1,b+1+m); int cnt = 0; for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=m;i++){ int u = find(b[i].u),v=find(b[i].v); if(u==v)continue; fa[u]=v; push(b[i].u,b[i].v,b[i].w); push(b[i].v,b[i].u,b[i].w); if(cnt==n-1)break; } Bfs(); } struct Tree{ Tree *ls,*rs; multiset<int>*v; int min_x; Tree() { ls=rs=NULL,v=NULL,min_x=inf; } void Push_up(){ #define MIN(x) ((x)?((x)->min_x):inf) min_x=min(MIN(ls),MIN(rs)); } void* operator new (size_t); void operator delete(void* p); }*root[MAXN],*S,*T; vector<Tree*>bin; void* Tree :: operator new(size_t size){ Tree *o; if(!bin.empty()){ o=bin.back(); bin.pop_back(); } else{ if(S==T){ S=new Tree[1<<15]; T=S+(1<<15); } o = S++; } o->ls=o->rs=NULL; o->v=NULL; o->min_x=inf; return o; } void Tree :: operator delete (void* p){ bin.push_back((Tree*)p); } void insert(Tree *&o,int l,int r,int x,int va){ if(!o)o = new Tree; if(l==r){ if(!o->v)o->v=new multiset<int>; o->v->insert(va); o->min_x=*(o->v->begin()); return; } int mid=l+r>>1; if(x<=mid)insert(o->ls,l,mid,x,va); else insert(o->rs,mid+1,r,x,va); o->Push_up(); } void erase(Tree *&o,int l,int r,int x,int va){ if(l==r){ o->v->erase(o->v->find(va)); if(o->v->empty()){ delete o->v; o->v=NULL; delete o; o=NULL; } else o->min_x=*(o->v->begin()); return; } int mid = l+r>> 1; if(x<=mid)erase(o->ls,l,mid,x,va); else erase(o->rs,mid+1,r,x,va); o->Push_up(); if(o->min_x==inf){ delete o; o=NULL; } } int query(Tree *o,int l,int r,int x,int y){ if(!o)return inf; if(x<=l&&r<=y)return o->min_x; int mid = l+r>>1,ans=inf; if(x<=mid)ans=min(ans,query(o->ls,l,mid,x,y)); if(mid<y)ans=min(ans,query(o->rs,mid+1,r,x,y)); return ans; } int Query(int x){ int ans = inf; if(val[x]!=1)ans=min(ans,query(root[x],1,k,1,val[x]-1)); if(val[x]!=k)ans=min(ans,query(root[x],1,k,val[x]+1,k)); return ans; } int main(){ //freopen("grass.in","r",stdin); //freopen("grass.out","w",stdout); bin.clear(); n=read<int>(); m=read<int>(); k=read<int>(); q=read<int>(); for(int i=1;i<=m;i++)scanf("%d%d%d",&b[i].u,&b[i].v,&b[i].w); for(int i=1;i<=n;i++)scanf("%d",&val[i]);Kr(); for(int i=2;i<=n;i++)insert(root[f[i]],1,k,val[i],cost[i]); for(int i=1;i<=n;i++)Ans.insert(last[i]=Query(i)); while(q--){ int pos=read<int>(),w=read<int>(); if(f[pos])erase(root[f[pos]],1,k,val[pos],cost[pos]); val[pos]=w; if(f[pos])insert(root[f[pos]],1,k,val[pos],cost[pos]); Ans.erase(Ans.find(last[pos])); Ans.insert(last[pos]=Query(pos)); if(f[pos]){ Ans.erase(Ans.find(last[f[pos]])); Ans.insert(last[f[pos]]=Query(f[pos])); } printf("%d\n",*(Ans.begin())); } }