Codeforces Round #378 (Div. 2)F
题目:一个带权连通无向图,给第i条边权值减1需要花费ci元,你一共有S元,求最小生成树。
容易得出钱全部花在一条边上是最优的。
我们先做一遍最小生成树。
然后我们枚举减哪一条边。
如果这条边是树上的,那么直接得出答案。
如果不是,我们可以用这一条边去替换u[i]、v[i]路径之间任意一条。所以我们用倍增(我sb了用的树链剖分)找到路径上最大的那一条替换,计算答案。
最后把这条边放进树里,再求一遍最小生成树就能输出方案了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MAX(a,b) a>b?a:b 5 #define N 210000 6 #define M 210000 7 #define mem(a) memset(a,0,sizeof(a)) 8 #define rep(i,n) for (int i=1;i<=(n);i++) 9 #define LL long long 10 using namespace std; 11 int uu,vv,root,ee,rr,ll,_,n,tot,e[M<<1],head[N],nex[N<<1]; 12 int id,p,q,m,top[N],siz[N],s[N],d[N],w[N],f[N],l[N<<2],r[N<<2]; 13 LL fuck,a[N<<2],orz,sum,S,ans,ma; 14 bool intree[M]; 15 struct lbz 16 { 17 int u,v,d; 18 LL w,c; 19 }ed[M]; 20 void add(int u,int v,int c) 21 { 22 e[++ee]=v;nex[ee]=head[u];head[u]=ee; 23 } 24 void build(int s,int ll,int rr) 25 { 26 l[s]=ll;r[s]=rr; 27 if (ll==rr) 28 a[s]=0; 29 else 30 { 31 int mid=(ll+rr)>>1; 32 build(s<<1,ll,mid); 33 build((s<<1)+1,mid+1,rr); 34 } 35 } 36 void add(int s) 37 { 38 if (l[s]==r[s]) 39 a[s]=rr; 40 else 41 { 42 if (r[s<<1]>=ll) 43 add(s<<1); 44 else 45 add((s<<1)+1); 46 a[s]=MAX(a[s<<1],a[(s<<1)+1]); 47 } 48 } 49 void sea(int s) 50 { 51 if (l[s]>rr || r[s]<ll) 52 return; 53 if (l[s]>=ll&&r[s]<=rr) 54 ans=MAX(ans,a[s]); 55 else 56 { 57 sea(s<<1); 58 sea((s<<1)+1); 59 } 60 } 61 void dfs1(int u) 62 { 63 int j=head[u]; 64 siz[u]=1; 65 while (j>0) 66 { 67 if (d[e[j]]==0) 68 { 69 d[e[j]]=d[u]+1; 70 f[e[j]]=u; 71 dfs1(e[j]); 72 if (siz[e[j]]>siz[s[u]]) 73 s[u]=e[j]; 74 siz[u]+=siz[e[j]]; 75 } 76 j=nex[j]; 77 } 78 } 79 void dfs2(int u) 80 { 81 int j=head[u]; 82 if (s[u]!=0) 83 { 84 w[s[u]]=++tot; 85 top[s[u]]=top[u]; 86 dfs2(s[u]); 87 } 88 while (j>0) 89 { 90 if (e[j]!=s[u]&&e[j]!=f[u]) 91 { 92 w[e[j]]=++tot; 93 top[e[j]]=e[j]; 94 dfs2(e[j]); 95 } 96 j=nex[j]; 97 } 98 } 99 void init() 100 { 101 orz=sum; 102 id=1; 103 mem(f); 104 } 105 bool cmp(lbz a,lbz b) 106 { 107 return a.w<b.w; 108 } 109 int find(int x) 110 { 111 if (f[x]==0) return x; 112 f[x]=find(f[x]); 113 return f[x]; 114 } 115 int main() 116 { 117 scanf("%d%d",&n,&m); 118 rep(i,m) 119 scanf("%I64d",&ed[i].w); 120 rep(i,m) 121 scanf("%I64d",&ed[i].c); 122 rep(i,m) 123 scanf("%d%d",&ed[i].u,&ed[i].v); 124 scanf("%I64d",&S); 125 rep(i,m) 126 ed[i].d=i; 127 sort(ed+1,ed+1+m,cmp); 128 rep(i,m) 129 { 130 p=find(ed[i].u); 131 q=find(ed[i].v); 132 if (p!=q) 133 { 134 f[p]=q; 135 intree[i]=1; 136 sum+=ed[i].w; 137 } 138 } 139 init(); 140 rep(i,m) 141 if (intree[i]==1) 142 { 143 add(ed[i].u,ed[i].v,ed[i].w); 144 add(ed[i].v,ed[i].u,ed[i].w); 145 } 146 build(1,1,n-1); 147 root=1;d[root]=1;top[root]=root; 148 dfs1(root); 149 dfs2(root); 150 rep(i,m) 151 { 152 if (intree[i]==0)continue; 153 if (d[ed[i].u]>d[ed[i].v]) 154 swap(ed[i].u,ed[i].v); 155 ll=w[ed[i].v];rr=ed[i].w; 156 add(1); 157 } 158 rep(i,m) 159 { 160 if (intree[i]==1) 161 { 162 fuck=sum-S/ed[i].c; 163 if (fuck<orz) 164 { 165 orz=fuck; 166 id=i; 167 } 168 continue; 169 } 170 uu=ed[i].u;vv=ed[i].v; 171 ma=0; 172 while (top[uu]!=top[vv]) 173 { 174 if (d[top[uu]]<d[top[vv]]) 175 swap(uu,vv); 176 ans=0;ll=w[top[uu]];rr=w[uu];sea(1); 177 ma=MAX(ma,ans); 178 uu=f[top[uu]]; 179 } 180 if (uu!=vv) 181 { 182 if (d[uu]<d[vv]) swap(uu,vv); 183 ans=0;ll=w[s[vv]];rr=w[uu];sea(1); 184 ma=MAX(ma,ans); 185 } 186 fuck=sum-ma+ed[i].w-S/ed[i].c; 187 if (fuck<orz) 188 { 189 orz=fuck; 190 id=i; 191 } 192 } 193 mem(f);mem(intree); 194 ed[id].w-=S/ed[id].c; 195 sort(ed+1,ed+1+m,cmp); 196 rep(i,m) 197 { 198 p=find(ed[i].u); 199 q=find(ed[i].v); 200 if (p!=q) 201 { 202 f[p]=q; 203 intree[i]=1; 204 } 205 } 206 printf("%I64d\n",orz); 207 rep(i,m) 208 if (intree[i]) 209 printf("%d %I64d\n",ed[i].d,ed[i].w); 210 return 0; 211 212 }
# | When | Who | Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|---|---|---|
22090610 | 2016-11-07 11:28:10 | lbz007 | F - Drivers Dissatisfaction | GNU C++ | Accepted | 608 ms | 34700 KB |
-------------------------------------------------------------------------
花有重开日,人无再少年