其他分享
首页 > 其他分享> > [bzoj4777]Switch Grass

[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