[bzoj4777]Switch Grass
作者:互联网
结论:最短路径一定是单独的一条边且在最小生成树上,可以用反证法证明。
那么求出最小生成树,对于每一个点建立一棵权值线段树,再对每一个权值线段树上的叶子节点开一个multiset,维护所有儿子中该种颜色的权值(普通节点仍维护区间最小值),答案也需要用multiset维护。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define mid (l+r>>1) 5 multiset<int>ans,s[N*3]; 6 struct ji{ 7 int nex,to,len; 8 }edge[N<<1]; 9 struct ji2{ 10 int x,y,z; 11 bool operator < (const ji2 &k)const{ 12 return z<k.z; 13 } 14 }a[N]; 15 int E,V,V2,n,m,q,head[N],f[N],r[N],sh[N],id[N*29],ls[N*29],rs[N*29],tr[N*29],c[N]; 16 int find(int k){ 17 if (k==f[k])return k; 18 return f[k]=find(f[k]); 19 } 20 void add(int x,int y,int z){ 21 edge[E].nex=head[x]; 22 edge[E].to=y; 23 edge[E].len=z; 24 head[x]=E++; 25 } 26 void update(int &k,int l,int r,int x,int y,int p,int c){ 27 if ((!k)&&(y==-1))return; 28 if (!k)k=++V; 29 if (l==r){ 30 if (!id[k])id[k]=++V2; 31 if (y!=-1) 32 if (p==1)s[id[k]].insert(y); 33 else s[id[k]].erase(s[id[k]].find(y)); 34 if ((c==x)||(!s[id[k]].size()))tr[k]=0x3f3f3f3f; 35 else tr[k]=(*s[id[k]].begin()); 36 return; 37 } 38 if (x<=mid)update(ls[k],l,mid,x,y,p,c); 39 else update(rs[k],mid+1,r,x,y,p,c); 40 tr[k]=min(tr[ls[k]],tr[rs[k]]); 41 } 42 void dfs(int k,int fa){ 43 f[k]=fa; 44 for(int i=head[k];i!=-1;i=edge[i].nex) 45 if (edge[i].to!=fa){ 46 dfs(edge[i].to,k); 47 sh[edge[i].to]=edge[i].len; 48 update(r[k],1,n,c[edge[i].to],edge[i].len,1,c[k]); 49 } 50 ans.insert(tr[r[k]]); 51 } 52 int main(){ 53 scanf("%d%d%*d%d",&n,&m,&q); 54 memset(head,-1,sizeof(head)); 55 tr[0]=0x3f3f3f3f; 56 for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); 57 sort(a+1,a+m+1); 58 for(int i=1;i<=n;i++)f[i]=i; 59 for(int i=1;i<=m;i++) 60 if (find(a[i].x)!=find(a[i].y)){ 61 f[find(a[i].x)]=find(a[i].y); 62 add(a[i].x,a[i].y,a[i].z); 63 add(a[i].y,a[i].x,a[i].z); 64 } 65 for(int i=1;i<=n;i++)scanf("%d",&c[i]); 66 dfs(1,0); 67 int x,y; 68 for(int i=1;i<=q;i++){ 69 scanf("%d%d",&x,&y); 70 if (f[x]){ 71 ans.erase(ans.find(tr[r[f[x]]])); 72 update(r[f[x]],1,n,c[x],sh[x],-1,c[f[x]]); 73 update(r[f[x]],1,n,y,sh[x],1,c[f[x]]); 74 ans.insert(tr[r[f[x]]]); 75 } 76 ans.erase(ans.find(tr[r[x]])); 77 update(r[x],1,n,c[x],-1,1,y); 78 c[x]=y; 79 update(r[x],1,n,c[x],-1,1,c[x]); 80 ans.insert(tr[r[x]]); 81 printf("%d\n",(*ans.begin())); 82 } 83 }View Code
标签:bzoj4777,线段,Switch,权值,multiset,维护,Grass,节点,define 来源: https://www.cnblogs.com/PYWBKTDA/p/11266526.html