题面:https://www.lydsy.com/JudgeOnline/problem.php?id=2238
思路:先求个最小生成树,然后就对最小生成树上的边做树剖,依次对非树边进行处理,维护非树边两端连成的路径的最小值(用非树边的权值维护),然后对于每个询问,求出覆盖在那条线段上的最小值,用real_sum(最小生成树的边权和)去加加减减就行了。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cstdlib> 6 #define min(a,b) ((a)<(b)?(a):(b)) 7 using namespace std; 8 const int maxn=50005,maxm=100005,maxw=10005,inf=1<<30; 9 int N,M,x,y,w,Q,edge_head[maxn],num_edge=0,edge_head2[maxn],num_edge2=0,fa[maxn],real_sum=0; 10 int size[maxn],son[maxn],seg[maxn],rev[maxn],f[maxn],dep[maxn],top[maxn],X,Y,_ans,T; 11 bool via[maxm],ans=1; 12 inline int rd(){ 13 int x=0,f=1;char c=getchar(); 14 while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} 15 while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} 16 return f*x; 17 } 18 struct Edge{ 19 int to,dis,nx,from; 20 }edge[maxm<<1]; 21 struct Edge2{ 22 int to,dis,nx,from,id; 23 }edge2[maxm]; 24 inline void Add_edge(int from,int to,int dis){ 25 edge[++num_edge].nx=edge_head[from]; 26 edge[num_edge].from=from; 27 edge[num_edge].to=to; 28 edge[num_edge].dis=dis; 29 edge_head[from]=num_edge; 30 return; 31 } 32 inline void Add_edge2(int from,int to,int dis){ 33 edge2[++num_edge2].nx=edge_head2[from]; 34 edge2[num_edge2].from=from; 35 edge2[num_edge2].to=to; 36 edge2[num_edge2].dis=dis; 37 edge2[num_edge2].id=num_edge2; 38 edge_head2[from]=num_edge2; 39 return; 40 } 41 inline bool cmp(const Edge2&a,const Edge2&b){ 42 if(a.dis<b.dis)return 1; 43 return 0; 44 } 45 inline int getf(int x){ 46 if(fa[x]==x)return x; 47 fa[x]=getf(fa[x]); 48 return fa[x]; 49 } 50 void Kruskal(){ 51 sort(edge2+1,edge2+num_edge2+1,cmp); 52 for(int i=1;i<=N;i++)fa[i]=i; 53 int num=0; 54 for(int i=1;i<=num_edge2;i++){ 55 int x=edge2[i].from,y=edge2[i].to; 56 int fx=getf(x),fy=getf(y); 57 if(fx!=fy){ 58 num++; 59 fa[fx]=fy; 60 via[edge2[i].id]=1; 61 real_sum+=edge2[i].dis; 62 if(num==N-1)break; 63 } 64 } 65 if(num!=N-1)ans=0; 66 return; 67 } 68 inline void Dfs1(int x,int _f){ 69 f[x]=_f; 70 size[x]=1; 71 dep[x]=dep[_f]+1; 72 for(int i=edge_head[x];i;i=edge[i].nx){ 73 int y=edge[i].to; 74 if(y!=_f&&((((i&1)==1)&&via[(i>>1)+1])||(((i&1)==0)&&via[i>>1]))){ 75 Dfs1(y,x); 76 size[x]+=size[y]; 77 if(size[y]>size[son[x]])son[x]=y; 78 } 79 } 80 return; 81 } 82 inline void Dfs2(int x){ 83 if(son[x]){ 84 int y=son[x]; 85 top[y]=top[x]; 86 seg[y]=++seg[0]; 87 rev[seg[0]]=y; 88 Dfs2(y); 89 } 90 for(int i=edge_head[x];i;i=edge[i].nx){ 91 int y=edge[i].to; 92 if(top[y]==0&&((((i&1)==1)&&via[(i>>1)+1])||(((i&1)==0)&&via[i>>1]))){ 93 top[y]=y; 94 seg[y]=++seg[0]; 95 rev[seg[0]]=y; 96 Dfs2(y); 97 } 98 } 99 return; 100 } 101 struct Tree{ 102 int l,r,mina,lazy; 103 }t[maxn<<3]; 104 inline void Build(int x,int l,int r){ 105 t[x].l=l;t[x].r=r;t[x].mina=inf;t[x].lazy=inf; 106 if(l==r)return; 107 int ls=x<<1,rs=x<<1|1,mid=(l+r)>>1; 108 Build(ls,l,mid);Build(rs,mid+1,r); 109 return; 110 } 111 inline void Pushdown(int x){ 112 int ls=x<<1,rs=x<<1|1,lazy=t[x].lazy; 113 if(lazy!=inf){ 114 t[ls].mina=min(t[ls].mina,lazy);t[rs].mina=min(t[rs].mina,lazy); 115 t[ls].lazy=min(t[ls].lazy,lazy);t[rs].lazy=min(t[rs].lazy,lazy); 116 t[x].lazy=inf; 117 } 118 return; 119 } 120 inline void Update(int x,int ql,int qr,int e){ 121 int l=t[x].l,r=t[x].r; 122 if(ql<=l&&r<=qr){ 123 t[x].mina=min(t[x].mina,e); 124 t[x].lazy=min(t[x].lazy,e); 125 return; 126 } 127 int ls=x<<1,rs=x<<1|1,mid=(l+r)>>1; 128 Pushdown(x); 129 if(ql<=mid)Update(ls,ql,qr,e); 130 if(qr>mid)Update(rs,ql,qr,e); 131 return; 132 } 133 inline void Query(int x,int q){ 134 int l=t[x].l,r=t[x].r; 135 if(q==l&&l==r){ 136 _ans=min(_ans,t[x].mina); 137 return; 138 } 139 int mid=(l+r)>>1,ls=x<<1,rs=x<<1|1; 140 Pushdown(x); 141 if(q<=mid)Query(ls,q); 142 else Query(rs,q); 143 return; 144 } 145 inline void Work(int x,int y,int dis){ 146 int fx=top[x],fy=top[y]; 147 while(fx!=fy){ 148 if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy); 149 Update(1,seg[fx],seg[x],dis); 150 x=f[fx];fx=top[x]; 151 } 152 if(dep[x]>dep[y])swap(x,y); 153 if(x==y)return; 154 Update(1,seg[x]+1,seg[y],dis); 155 return; 156 } 157 int main(){ 158 N=rd();M=rd(); 159 for(int i=1;i<=M;i++){ 160 x=rd();y=rd();w=rd(); 161 Add_edge2(x,y,w); 162 Add_edge(x,y,w); 163 Add_edge(y,x,w); 164 } 165 Kruskal(); 166 scanf("%d",&Q); 167 Dfs1(1,0); 168 seg[0]=seg[1]=rev[1]=top[1]=1; 169 Dfs2(1); 170 Build(1,1,seg[0]); 171 for(int i=1;i<=M;i++)if(via[i]==0)Work(edge[i<<1].from,edge[i<<1].to,edge[i<<1].dis); 172 while(Q--){ 173 scanf("%d",&T); 174 if(ans==0){ 175 puts("Not connected"); 176 continue; 177 } 178 if(via[T]==0)printf("%d\n",real_sum); 179 else{ 180 X=edge[T<<1].from,Y=edge[T<<1].to;_ans=inf; 181 if(dep[X]>dep[Y])Query(1,seg[X]);else Query(1,seg[Y]); 182 if(_ans==inf){ 183 puts("Not connected"); 184 continue; 185 } 186 _ans=real_sum-edge[T<<1].dis+_ans; 187 printf("%d\n",_ans); 188 } 189 } 190 return 0; 191 }
后记:“&”的优先级小于“==”的优先级;线段树查询时要注意ql不能大于qr;边权下移后处理点权时要小心;什么情况要pushdown、pushup要考虑清楚;我的线段树真菜