NOI 2014 魔法森林(BZOJ 3669) 题解

对边按a权值排序,按b权值建LCT,按排序后的顺序依次加边。如果加边后形成环则删除环上最大的边。如果起点终点联通则更新答案。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #define rep(i,n) for(int i=0;i<n;++i)
  4 const int MAXN=50000+5;
  5 const int MAXM=100000+5;
  6 const int INF=~0U>>1;
  7 struct Node{
  8     int mxv,v;
  9     Node* p,*ch[2],*mx;
 10     int e;
 11     bool rev;
 12     Node() {mxv=v=-1;}
 13     inline bool d() const
 14     {
 15         return p->ch[1]==this;
 16     }
 17     inline void revIt()
 18     {
 19         rev^=1;
 20         std::swap(ch[0],ch[1]);
 21     }
 22     inline void setc(Node* t,bool d)
 23     {
 24         ch[d]=t;
 25         t->p=this;
 26     }
 27     inline void maintain()
 28     {
 29         mxv=v;mx=this;
 30         rep(i,2) if(ch[i]->mxv>mxv)
 31         {
 32             mxv=ch[i]->mxv;
 33             mx=ch[i]->mx;
 34         }
 35     }
 36     inline bool isRoot() const;
 37     inline void pushdown();
 38 }Tnull,*null=&Tnull;
 39 inline bool Node::isRoot() const
 40 {
 41     return p==null || (p->ch[0]!=this && p->ch[1]!=this);
 42 }
 43 inline void Node::pushdown()
 44 {
 45     if(rev)
 46     {
 47         rev=0;
 48         rep(i,2) if(ch[i]!=null)
 49             ch[i]->revIt();
 50     }
 51 }
 52 inline void rot(Node* t)
 53 {
 54     Node* p=t->p;
 55     p->pushdown();t->pushdown();
 56     bool d=t->d();
 57     if(!p->isRoot()) p->p->setc(t,p->d());
 58     else t->p=p->p;
 59     p->setc(t->ch[d^1],d);
 60     t->setc(p,d^1);
 61     p->maintain();
 62 }
 63 inline void splay(Node* t)
 64 {
 65     t->pushdown();
 66     while(!t->isRoot())
 67     {
 68         if(t->p->isRoot()) rot(t);
 69         else t->d()==t->p->d()?(rot(t->p),rot(t)):(rot(t),rot(t));
 70     }
 71     t->maintain();
 72 }
 73 inline void access(Node* u)
 74 {
 75     for(Node* v=null;u!=null;v=u,u=u->p)
 76     {
 77         splay(u);
 78         u->setc(v,1);
 79         u->maintain();
 80     }
 81 }
 82 inline void makeRoot(Node* u)
 83 {
 84     access(u);
 85     splay(u);
 86     u->revIt();
 87 }
 88 inline void link(Node* u,Node* v)
 89 {
 90     makeRoot(u);u->p=v;
 91 }
 92 inline void cut(Node* u,Node* v)
 93 {
 94     makeRoot(u);
 95     access(v);
 96     splay(v);
 97     if(v->ch[0]==u)
 98     {
 99         v->setc(null,0);
100         v->maintain();
101         u->p=null;
102     }
103 }
104 inline Node* find(Node* u)
105 {
106     for(;u->p!=null;u=u->p);
107     return u;
108 }
109 inline void change(Node* u,int v)
110 {
111     access(u);
112     splay(u);
113     u->v=v;
114     u->maintain();
115 }
116 inline void getMax(Node* u,Node* v,int& maxv,int& e,Node*& mx)
117 {
118     makeRoot(u);
119     access(v);
120     splay(v);
121     maxv=v->mxv;
122     mx=v->mx;
123     e=v->mx->e;
124 }
125 inline int query(Node* u,Node* v)
126 {
127     makeRoot(u);
128     access(v);
129     splay(v);
130     return v->mxv;
131 }
132 Node mem[MAXN+MAXM],*C=mem;
133 inline Node* newNode(int v,int e)
134 {
135     C->p=C->ch[0]=C->ch[1]=null;
136     C->rev=0;
137     C->v=C->mxv=v;
138     C->mx=C;
139     C->e=e;
140     return C++;
141 }
142 struct Edge{
143     int u,v,a,b;
144     Edge() {}
145     Edge(int u,int v,int a,int b):u(u),v(v),a(a),b(b) {}
146     bool operator<(const Edge& rhs) const
147     {
148         return a<rhs.a;
149     }
150 }edges[MAXM];
151 Node* pt[MAXN+MAXM];
152 int n,m;
153 int ans=INF;
154 int main()
155 {
156     //freopen("1.in","r",stdin);
157     scanf("%d%d",&n,&m);
158     rep(i,m)
159     {
160         int u,v,a,b;
161         scanf("%d%d%d%d",&u,&v,&a,&b);
162         edges[i]=Edge(u,v,a,b);
163     }
164     std::sort(edges,edges+m);
165     rep(i,n) pt[i+1]=newNode(0,-1);
166     rep(i,m) pt[i+n+1]=newNode(edges[i].b,i);
167     rep(i,m)
168     {
169         Edge e=edges[i];
170         if(find(pt[e.u])!=find(pt[e.v])) link(pt[e.u],pt[i+n+1]),link(pt[e.v],pt[i+n+1]);
171         else
172         {
173             int en,maxv;
174             Node* mx;
175             getMax(pt[e.u],pt[e.v],maxv,en,mx);
176             if(maxv>e.b)
177             {
178                 cut(pt[edges[en].u],pt[en+n+1]);
179                 cut(pt[edges[en].v],pt[en+n+1]);
180                 link(pt[e.u],pt[i+n+1]);
181                 link(pt[e.v],pt[i+n+1]);
182             }
183         }
184         if(find(pt[1])==find(pt[n])) ans=std::min(ans,query(pt[1],pt[n])+edges[i].a);
185     }
186     printf("%d\n",ans==INF?-1:ans);
187     return 0;
188 }
View Code

 

posted @ 2015-03-30 18:05  lowsfish  阅读(240)  评论(0编辑  收藏  举报