bzoj2001 城市建设

bzoj崩了3天了......本人目前处在无题可交的状态,郁闷啊。不过TY复活了,看到以前写过的代码有点小激动。

切入正题,这个题想了好久才写,主体还是分治,只是中间处理部分比较巧妙。这个题GYZ在wc上讲过,思路也很清晰,就是不太好写。

过程主要分两个部分(我直接粘解题报告了):

1. Contraction
把 L..R要修改的所有边权暂时标记为-∞;
对图做 MST;
此时观察图中不是-∞但被选入 MST的边集;
它们在 L..R的询问中也一定会被选入;
于是可以直接先用这些边把点集做合并操作。这样图的点数被缩小;
还原边权标记.
2. Reduction
把 L..R要修改的所有边权暂时标记为∞;
对图做 MST;
此时观察图中不是∞但没被选入 MST的边集;
它们在 L..R的询问中是无意义的,可以直接删除。这样图的边数被缩小;
还原边权标记.

这样做下去,等到L==R的时候,此时图已经被我们缩到了最小,做一遍mst即可。

注意contraction的时候缩完的边要累积到答案里面,然后就是每走到一个L==R的过程,就要令当前修改操作生效,因为它对后面的操作都有影响。

对于图的处理,最好是每层记录一个图,这样回溯的时候比较方便还原,另外要记录一个数组ci表示原来标号为i的边在当前边表中的位置。

city
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #define maxn 60000
  7 #define maxm 120000
  8 #define inf 2147483647
  9 using namespace std;
 10 struct et
 11 {
 12     int s,t,pos,val;
 13 }e[22][maxm],d[maxm],t[maxm];
 14 struct adj
 15 {
 16     int x,z;
 17 }q[maxn];
 18 int a[maxm],c[maxm];
 19 int f[maxn],sum[maxn],size[maxn];
 20 long long ans[maxm];
 21 int n,m,p;
 22 
 23 inline void fill(int tot)
 24 {
 25     for (int i=1;i<=tot;i++) 
 26         f[d[i].s]=f[d[i].t]=0,size[d[i].s]=size[d[i].t]=1;
 27 }
 28 inline int find(int i)
 29 {
 30     return (!f[i])?i:f[i]=find(f[i]);
 31 }
 32 inline void merge(int x,int y)
 33 {
 34     int fx=find(x),fy=find(y);
 35     if (size[fx]<=size[fy]) f[fx]=fy,size[fy]+=size[fx];
 36     else f[fy]=fx,size[fx]+=size[fy];
 37 }
 38 
 39 inline bool cmp(et a,et b)
 40 {
 41     return a.val<b.val;
 42 }
 43 
 44 inline void reduce(int &tot)
 45 {
 46     int tmp=0;
 47     fill(tot);
 48     sort(d+1,d+tot+1,cmp);
 49     for (int i=1;i<=tot;i++)
 50     {
 51         if (find(d[i].s)!=find(d[i].t))
 52         {
 53             merge(d[i].s,d[i].t);
 54             t[++tmp]=d[i];
 55             c[d[i].pos]=tmp;
 56         }
 57         else 
 58         if (d[i].val==inf)
 59         {
 60             t[++tmp]=d[i];
 61             c[d[i].pos]=tmp;
 62         }
 63     }
 64     for (int i=1;i<=tmp;i++) d[i]=t[i];
 65     tot=tmp;
 66 }
 67 
 68 inline void connect(int &tot,long long &cnt)
 69 {
 70     int tmp=0;
 71     fill(tot);
 72     sort(d+1,d+tot+1,cmp);
 73     for (int i=1;i<=tot;i++)
 74     {
 75         if (find(d[i].s)!=find(d[i].t)) 
 76         {
 77             merge(d[i].s,d[i].t);
 78             t[++tmp]=d[i];
 79         }
 80     }
 81     for (int i=1;i<=tmp;i++) f[t[i].s]=f[t[i].t]=0,size[t[i].s]=size[t[i].t]=1;
 82     for (int i=1;i<=tmp;i++)
 83         if (t[i].val!=-inf&&find(t[i].s)!=find(t[i].t))
 84             merge(t[i].s,t[i].t),cnt+=t[i].val;
 85     tmp=0;
 86     for (int i=1;i<=tot;i++)
 87         if (find(d[i].s)!=find(d[i].t)) 
 88         {
 89             t[++tmp]=d[i];
 90             c[d[i].pos]=tmp;
 91             t[tmp].s=find(d[i].s);
 92             t[tmp].t=find(d[i].t);
 93         }
 94     for (int i=1;i<=tmp;i++) d[i]=t[i];
 95     tot=tmp;
 96 }
 97 
 98 inline void solve(int l,int r,int now,long long cnt)
 99 {
100     int tot=sum[now];
101     if (l==r) a[q[l].x]=q[l].z;//修改生效
102     for (int i=1;i<=tot;i++) e[now][i].val=a[e[now][i].pos];
103     for (int i=1;i<=tot;i++) d[i]=e[now][i],c[d[i].pos]=i;  
104     if (l==r)
105     {
106         ans[l]=cnt;
107         fill(tot);
108         sort(d+1,d+tot+1,cmp);
109         for (int i=1;i<=tot;i++)
110             if (find(d[i].s)!=find(d[i].t))
111                 merge(d[i].s,d[i].t),ans[l]+=d[i].val;
112         return ;
113     }
114     for (int i=l;i<=r;i++) d[c[q[i].x]].val=-inf;
115     connect(tot,cnt);
116     for (int i=l;i<=r;i++) d[c[q[i].x]].val=inf;
117     reduce(tot);
118     for (int i=1;i<=tot;i++) e[now+1][i]=d[i];
119     sum[now+1]=tot;
120     int mid=(l+r)>>1;
121     solve(l,mid,now+1,cnt);
122     solve(mid+1,r,now+1,cnt);
123 }    
124 
125 int main()
126 {
127     //freopen("city.in","r",stdin);
128     //freopen("city.out","w",stdout);
129     scanf("%d%d%d",&n,&m,&p);
130     int x,y;
131     for (int i=1;i<=m;i++)
132     {
133         scanf("%d%d%d",&x,&y,&a[i]);
134         e[0][i].s=x; e[0][i].t=y; e[0][i].val=a[i];
135         e[0][i].pos=i;
136     }
137     for (int i=1;i<=p;i++)
138         scanf("%d%d",&q[i].x,&q[i].z);
139     sum[0]=m;
140     solve(1,p,0,0);
141     for (int i=1;i<=p;i++)
142         printf("%lld\n",ans[i]);
143     return 0;
144 }

 

代码冗长,速度还可以。

 

转载于:https://www.cnblogs.com/zig-zag/archive/2013/05/02/3054932.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值