zoukankan      html  css  js  c++  java
  • 「NOI 2014」魔法森林

    题目链接

    戳我

    (Solution)

    两个变量,emm...不好搞啊。

    于是我们可以按照(A)排序。然后动态加边,因为(A)是越来越大,所以不需要管他,只要使得(1)$n$的路径中$B$最大值最小。这用LCT维护生成树就好了,模板题。每次加边后满足$1$(n)有路径的时候将
    此时最大的(B)+当前(A),去(min),最后输出即可

    (Code)

    #include<bits/stdc++.h>
    #define rg register
    #define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
    using namespace std;
    int read(){
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
        return f*x;
    }
    struct node {
        int v,lazy,ch[2],fa;
    }a[2000001];
    int v[2000001],pre[2000001];
    int max(int x,int y){
        return v[x]>v[y]?x:y;
    }
    void pushup(int x){
        a[x].v=max(x,max(a[a[x].ch[0]].v,a[a[x].ch[1]].v));
    }
    bool nroot(int x){
        return a[a[x].fa].ch[0]==x||a[a[x].fa].ch[1]==x;
    }
    void work(int x){
        swap(a[x].ch[1],a[x].ch[0]),a[x].lazy^=1;
    }
    void pushdown(int x){
        if(a[x].lazy){
    		if(a[x].ch[0]) work(a[x].ch[0]);
    		if(a[x].ch[1]) work(a[x].ch[1]);
    		a[x].lazy=0;
        }
    }
    void pushall(int x){
        if(nroot(x)) pushall(a[x].fa);
        pushdown(x);
    }
    void rotate(int x){
        int y=a[x].fa,z=a[y].fa,k=a[y].ch[1]==x;
        if(nroot(y)) a[z].ch[a[z].ch[1]==y]=x;
        a[x].fa=z,a[y].ch[k]=a[x].ch[k^1],a[a[x].ch[k^1]].fa=y;
        a[x].ch[k^1]=y,a[y].fa=x,pushup(y),pushup(x);
    }
    void splay(int x){
        pushall(x);
        while(nroot(x)){
    		int y=a[x].fa,z=a[y].fa;
    		if(nroot(y))
    			(a[y].ch[1]==x)^(a[z].ch[1]==y)?rotate(x):rotate(y);
    		rotate(x);
        }
        pushup(x);
    }
    void access(int x){
        for(int y=0;x;y=x,x=a[x].fa)
    		splay(x),a[x].ch[1]=y,pushup(x);
    }
    void makeroot(int x){
        access(x),splay(x),work(x);
    }
    int findroot(int x){
        access(x),splay(x);
        while(a[x].ch[0]) pushdown(x),x=a[x].ch[0];
        splay(x);
        return x;
    }
    void splix(int x,int y){
        makeroot(x),access(y),splay(y);
    }
    void link(int x,int y){
        makeroot(x);
        if(findroot(y)!=x)
    		a[x].fa=y;
    }
    void cut(int x,int y){
        makeroot(x);
        if(findroot(y)!=x||a[y].fa!=x||a[y].ch[0]) return;
        a[x].ch[1]=a[y].fa=0,pushup(x);
    }
    struct node1 {
        int x,y,z,v;
    }b[1000010];
    bool cmp(const node1 & a , const node1 & b ){
        return a.z<b.z;
    }
    int find(int x){
        return pre[x]==x?x:pre[x]=find(pre[x]);
    }
    int main(){
        int n=read(),m=read(),x,minx=2147483647;
        for(int i=1;i<=m;i++)
    		b[i].x=read(),b[i].y=read(),b[i].z=read(),b[i].v=read();
        sort(b+1,b+1+m,cmp);
        for(int i=1;i<=n;i++) pre[i]=i;
        for(int i=1;i<=m;i++) v[i+n]=b[i].v;
        for(int i=1;i<=m;i++){
    		int fx=find(b[i].x),fy=find(b[i].y);
    		if(fx!=fy)
    			link(b[i].x,i+n),link(b[i].y,i+n),pre[fx]=fy;
    		else if(b[i].x!=b[i].y){
    			splix(b[i].x,b[i].y),x=a[b[i].y].v;
    			if(v[x]>b[i].v)
    				cut(b[x-n].x,x),cut(b[x-n].y,x),link(b[i].x,i+n),link(b[i].y,i+n);
    		}
    		if(find(1)==find(n))
    			splix(1,n),minx=min(minx,v[a[n].v]+b[i].z);
        }
    	if(minx==2147483647) puts("-1"),exit(0);
        printf("%d",minx);
        return 0;
    }
    
  • 相关阅读:
    流程设计器的界面设计
    业务系统如何集成工作流系统
    初生牛犊式工作流系统
    任务提醒功能的实现
    动态分支在工作流中的应用
    流程实例运行轨迹的运用
    工作流系统之轨迹备注
    曾经迷茫的起点,多年后终于明白了(续)
    自己编写多线程类并发测试工作流系统(仿吉日老大的测试方法)
    Web自定义表单工具和协同办公系统之集成(1)
  • 原文地址:https://www.cnblogs.com/hbxblog/p/10756207.html
Copyright © 2011-2022 走看看