[BJOI2010]次小生成树

OJ题号:
  BZOJ1977、COGS2453

题目大意:
  给你一个无向连通图,求严格次小生成树。

思路:
  对于一般次小生成树,我们有一个结论:一般次小生成树一定可以通过替换掉最小生成树某一条边得到。
  因此对于一般次小生成树,我们只需要枚举不在MST上的每一条边,并枚举这条边对应两点路径上的所有边,尝试交换这两条边即可。
  显然枚举树上每一条边的复杂度是O(n)的,会TLE,因此我们可以用树剖或者树上倍增的方法记录区间最大边。
  然而这题要求的是严格次小生成树,所以万一你枚举的这两条边相等就WA了。
  为了保险起见,我们再记录区间最大边的同时,还要记录区间严格次大边。
  然后枚举的时候只要判断当前区间最大边是否和那条非树边相等,如果相等的话就取那条次大边即可。
  一开始因为没有权限号就去COGS上交,然后随随便便就A了,还跑了Rank1。
  但是据说那里数据比较水,就找q234rty借了权限号,去BZOJ上交,果然WA了。
  随机了一个小数据,发现是最后倍增求最大树边的时候最后一层没跳上去。
  去网上拉了一个程序对拍,发现无限WA。
  拿了一个数据手动模拟了一遍,发现原来是网上的题解错了。。

  1 #include<queue>
  2 #include<cstdio>
  3 #include<cctype>
  4 #include<vector>
  5 #include<algorithm>
  6 inline int getint() {
  7     register char ch;
  8     while(!isdigit(ch=getchar()));
  9     register int x=ch^'0';
 10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 11     return x;
 12 }
 13 const long long inf=0x7fffffffffffffffll;
 14 const int V=100001,logV=18;
 15 inline int log2(const float x) {
 16     return ((unsigned&)x>>23&255)-127;
 17 }
 18 class DisjointSet {
 19     private:
 20         int anc[V];
 21         int Find(const int &x) {
 22             return x==anc[x]?x:anc[x]=Find(anc[x]);
 23         }
 24     public:
 25         DisjointSet() {
 26             for(register int i=0;i<V;i++) {
 27                 anc[i]=i;
 28             }
 29         }
 30         void Union(const int &x,const int &y) {
 31             anc[Find(x)]=Find(y);
 32         }
 33         bool isConnected(const int &x,const int &y) {
 34             return Find(x)==Find(y);
 35         }
 36 };
 37 DisjointSet s;
 38 struct Edge1 {
 39     int u,v,w;
 40     bool inMST;
 41     bool operator < (const Edge1 &another) const {
 42         return w<another.w;
 43     }
 44 };
 45 std::vector<Edge1> e1;
 46 struct Edge {
 47     int to,w;
 48 };
 49 std::vector<Edge> e[V];
 50 inline void add_edge(const int &u,const int &v,const int &w) {
 51     e[u].push_back((Edge){v,w}); 
 52 }
 53 long long mst=0;
 54 inline void kruskal() {
 55     std::sort(e1.begin(),e1.end());
 56     for(register unsigned i=0;i<e1.size();i++) {
 57         const int &u=e1[i].u,&v=e1[i].v,&w=e1[i].w;
 58         if(s.isConnected(u,v)) continue;
 59         s.Union(u,v);
 60         add_edge(u,v,w);
 61         add_edge(v,u,w);
 62         e1[i].inMST=true;
 63         mst+=w;
 64     }
 65 }
 66 int anc[V][logV],max[V][logV],max2[V][logV];
 67 int dep[V];
 68 std::queue<int> q;
 69 inline void bfs() {
 70     q.push(1);
 71     while(!q.empty()) {
 72         const int x=q.front();
 73         q.pop();
 74         dep[x]=dep[anc[x][0]]+1;
 75         for(register int i=1;i<=log2(dep[x]);i++) {
 76             anc[x][i]=anc[anc[x][i-1]][i-1];
 77             max[x][i]=std::max(max[x][i-1],max[anc[x][i-1]][i-1]);
 78             if(max[x][i-1]!=max[anc[x][i-1]][i-1]) {
 79                 max2[x][i]=std::min(max[x][i-1],max[anc[x][i-1]][i-1]);
 80             } else {
 81                 max2[x][i]=std::max(max2[x][i-1],max2[anc[x][i-1]][i-1]);
 82             }
 83         }
 84         for(register unsigned i=0;i<e[x].size();i++) {
 85             const int &y=e[x][i].to;
 86             if(y==anc[x][0]) continue;
 87             anc[y][0]=x;
 88             max[y][0]=e[x][i].w;
 89             q.push(y);
 90         }
 91     }
 92 }
 93 inline int maxEdge(int x,int y,const int &w) {
 94     int tmax=0;
 95     while(dep[x]!=dep[y]) {
 96         if(dep[x]<dep[y]) std::swap(x,y);
 97         for(register int i=log2(dep[x]);i>=0;i--) {
 98             if(dep[anc[x][i]]>=dep[y]) {
 99                 if(max[x][i]<w) {
100                     tmax=std::max(tmax,max[x][i]);
101                 } else if(max2[x][i]<w) {
102                     tmax=std::max(tmax,max2[x][i]);
103                 }
104                 x=anc[x][i];
105             }
106         }
107     }
108     if(x==y) return tmax;
109     for(register int i=log2(dep[x]);i>=0;i--) {
110         if(anc[x][i]!=anc[y][i]) {
111             if(max[x][i]<w) {
112                 tmax=std::max(tmax,max[x][i]);
113             } else if(max2[x][i]<w) {
114                 tmax=std::max(tmax,max2[x][i]);
115             }
116             if(max[y][i]<w) {
117                 tmax=std::max(tmax,max[y][i]);
118             } else if(max2[y][i]<w) {
119                 tmax=std::max(tmax,max2[y][i]);
120             }
121             x=anc[x][i],y=anc[y][i];
122         }
123     }
124     if(max[x][0]<w) {
125         tmax=std::max(tmax,max[x][0]);
126     } else if(max2[x][0]<w) {
127         tmax=std::max(tmax,max2[x][0]);
128     }
129     if(max[y][0]<w) {
130         tmax=std::max(tmax,max[y][0]);
131     } else if(max2[y][0]<w) {
132         tmax=std::max(tmax,max2[y][0]);
133     }
134     return tmax;
135 }
136 int main() {
137     #ifndef ONLINE_JUDGE
138         freopen("secmst.in","r+",stdin);
139         freopen("secmst.out","w+",stdout);
140     #endif
141     int n=getint(),m=getint();
142     for(register int i=1;i<=m;i++) {
143         const int u=getint(),v=getint(),w=getint();
144         e1.push_back((Edge1){u,v,w,false});
145     }
146     kruskal();
147     bfs();
148     long long ans=inf;
149     for(register unsigned i=0;i<e1.size();i++) {
150         if(e1[i].inMST) continue;
151         const int &u=e1[i].u,&v=e1[i].v,&w=e1[i].w;
152         ans=std::min(ans,mst-maxEdge(u,v,w)+w);
153     }
154     printf("%lld\n",ans);
155     #ifndef ONLINE_JUDGE
156         fclose(stdin),fclose(stdout);
157     #endif
158     return 0;
159 } 

 

posted @ 2017-09-21 10:07  skylee03  阅读(98)  评论(0编辑  收藏  举报