zoukankan      html  css  js  c++  java
  • 洛谷2387 NOI2014魔法森林(LCT维护最小生成树)

    本题是运用LCT来维护一个最小生成树。
    是一个经典的套路

    题目中求的是一个(max(a_i)+max(b_i))尽可能小的路径。

    那么这种的一个套路就是,先按照一维来排序,然后用LCT维护另一维

    那么这个对于这个题来说,我们考虑,可以先按照a从小到大排序,然后顺次加入每条边,这样每次加入的边一定是有可能会更新到(ans)的.

    对于一条边(u->v),如果(u)(v)不在一个联通块里面的话,那么就直接连上这个边,然后尝试更新答案

    如果在同一个联通块里面呢,我们就判断(u)(v)的路径上的(b)值的最大值,如果小于当前的边的(b),那么这条边就有可能会更新答案,所以就把原来的边删掉,然后(link)当前边。
    不过一个需要注意的地方就是
    每次不管是加入或者不加入,都需要对(ans)进行更新(不需要担心答案的覆盖,因为不优的答案永远是会被优的答案提前更新到一次的)

    同时维护边的时候,我是选择了(map)

    上代码

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<set>
    
    using namespace std;
    
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    
    const int maxn = 4e5+1e2;
    
    struct Node{
    	int x,y,a,b;
    };
    
    Node a[maxn];
    
    int ch[maxn][3];
    int fa[maxn],rev[maxn];
    int mx[maxn],mxpos[maxn];
    int val[maxn];
    int n,m;
    
    int son(int x)
    {
    	if (ch[fa[x]][0]==x) return 0;
    	else return 1;
    }
    
    bool notroot(int x)
    {
    	return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
    }
    
    void update(int x)
    {
    	mx[x]=val[x];
    	mxpos[x]=x;
    	if (ch[x][0])
    	{
    		if (mx[ch[x][0]]>mx[x])
    		{
    			mx[x]=mx[ch[x][0]];
    			mxpos[x]=mxpos[ch[x][0]];
    		}
    	}
    	if (ch[x][1])
    	{
    		if (mx[ch[x][1]]>mx[x])
    		{
    			mx[x]=mx[ch[x][1]];
    			mxpos[x]=mxpos[ch[x][1]];
    		}
    	}
    }
    
    void reverse(int x)
    {
    	swap(ch[x][0],ch[x][1]);
    	rev[x]^=1;
    }
    
    void pushdown(int x)
    {
    	if (rev[x])
    	{
    		if (ch[x][1]) reverse(ch[x][1]);
    		if (ch[x][0]) reverse(ch[x][0]);
    		rev[x]=0;
    	}
    }
    
    void rotate(int x)
    {
    	int y=fa[x],z=fa[y];
    	int b=son(x),c=son(y);
    	if (notroot(y)) ch[z][c]=x;
    	fa[x]=z;
    	ch[y][b]=ch[x][!b];
    	fa[ch[x][!b]]=y;
    	ch[x][!b]=y;
    	fa[y]=x;
    	update(y);
        update(x);
    }
    
    int st[maxn];
    
    void splay(int x)
    {
      int y=x,cnt=0;
      st[++cnt]=y;
      while (notroot(y)) y=fa[y],st[++cnt]=y;
      while (cnt) pushdown(st[cnt--]);
      while (notroot(x))
      {
      	int y=fa[x],z=fa[y];
      	int b=son(x),c=son(y);
      	if (notroot(y))
      	{
      		if (b==c) rotate(y);
      		else rotate(x);
    	}
    	rotate(x);
      }
      update(x);
    }
    
    void access(int x)
    {
    	for (int y=0;x;y=x,x=fa[x])
    	{
    		splay(x);
    		ch[x][1]=y;
    		update(x);
    	}
    	//for(expose();pfa;splay()) pfa->expose(),pfa->set_ch(1,this),pfa=0;
    	//expose(x);while(splice(x));return 0;
    }
    
    void makeroot(int x)
    {
    	access(x);
    	splay(x);
    	reverse(x);
    }
    
    int findroot(int x)
    {
    	access(x);
    	splay(x);
    	while (ch[x][0])
    	{
    		pushdown(x);
    		x=ch[x][0];
    	}
    	return x;
    }
    
    void split(int x,int y)
    {
    	makeroot(x);
    	access(y);
    	splay(y);
    }
    
    void link(int x,int y)
    {
    	makeroot(x);
    	if (findroot(y)!=x) fa[x]=y;
    }
    
    void cut(int x,int y)
    {
    	split(x,y);
    	if (ch[x][0] || ch[x][1] || fa[x]!=y || ch[y][son(x)^1]) return;
    	fa[x]=ch[y][0]=0;
    }
    
    int ans=1e9;
    
    bool cmp(Node a,Node b)
    {
    	return a.a<b.a;
    }
    
    int main()
    {
       n=read(),m=read();
       for (int i=1;i<=m;i++)
       {
       	  a[i].x=read(),a[i].y=read();
       	  a[i].a=read(),a[i].b=read();
       }
       sort(a+1,a+1+m,cmp);
       for (int i=1;i<=m;i++)
       {
       	   val[i+n]=a[i].b;
       	   if (findroot(a[i].x)==findroot(a[i].y))
       	   {
       	   	  split(a[i].x,a[i].y);
       	   	  int now = mxpos[a[i].y];
       	   	  if (mx[a[i].y]<a[i].b) continue;
       	   	  now-=n;
       	   	  cut(a[now].x,now+n);
       	   	  cut(a[now].y,now+n);
       	   	  //cout<<a[now].x<<" "<<a[now].y<<endl;
       	   	  link(a[i].x,i+n);
       	   	  link(a[i].y,i+n);
           }
           else
           {
    	      val[i+n]=a[i].b;
           	  link(a[i].x,i+n);
           	  link(a[i].y,i+n); 
    	   }
    	   if (findroot(1)!=findroot(n)) continue;
    	   split(1,n);
    	   ans=min(ans,mx[n]+a[i].a);
    	  // cout<<ans<<endl;
       }
       if (ans==1e9) ans=-1;
       cout<<ans;
       return 0;
    }
    
    
  • 相关阅读:
    Codeforces Round #350 (Div. 2) F. Restore a Number 模拟
    Codeforces Round #374 (Div. 2) C. Journey DP
    Codeforces Round #375 (Div. 2) D. Lakes in Berland DFS
    Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) D. Generating Sets 堆
    Ubuntu 安装 搜狗输入法
    Ubuntu 搜索不到WIFI或连接不上的解决方法
    Ubuntu 线缆被拔出问题
    Codeforces Round #357 (Div. 2) D. Gifts by the List DFS
    Codeforces Round #357 (Div. 2) C. Heap Operations 优先队列
    Codeforces Round #356 (Div. 2) C. Bear and Prime 100 交互题
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10161409.html
Copyright © 2011-2022 走看看