zoukankan      html  css  js  c++  java
  • [NOI 2014]魔法森林

    题意:求带修最短路。

    思路:一开始想的就是LCT维护一棵最小生成树,后来发现还有动态开点SPFA的这种操作...神了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    const int N=300010;
    
    int ch[N][2],pre[N],v[N],pos[N],fa[N];
    
    bool rev[N];
    
    int Q[N],n,m;
    
    struct node
    {
    	int x,y,a,b;
    }po[N];
    
    
    int cmp(const node &A,const node &B) {
    	if (A.a!=B.a) return A.a<B.a;
    	else return A.b<B.b;
    }
    
    int get(int num) {
    	return ch[pre[num]][0]==num? 0:1;
    }
    
    int isroot(int num) { 
    	return ch[pre[num]][0]!=num&&ch[pre[num]][1]!=num;
    }
    
    void update(int num) {
    	if (!num) return;
    	pos[num]=num;
    	int l=ch[num][0];
    	int r=ch[num][1];
    	if (l&&v[pos[l]]>v[pos[num]]) pos[num]=pos[l];
    	if (r&&v[pos[r]]>v[pos[num]]) pos[num]=pos[r];
    }
    
    void push(int num) {
    	if (!num) return;
    	if (rev[num]) {
    		if (ch[num][0]) rev[ch[num][0]]^=1;
    		if (ch[num][1]) rev[ch[num][1]]^=1;
    		swap(ch[num][0],ch[num][1]);
    		rev[num]^=1;
    	}
    }
    
    void rotate(int num) {
    	int fa=pre[num];
    	int grand=pre[fa];
    	int wh=get(num);
    	if (!isroot(fa)) ch[grand][ch[grand][0]==fa? 0:1]=num;
    	pre[num]=grand;
    	ch[fa][wh]=ch[num][wh^1];
    	pre[ch[fa][wh]]=fa;
    	ch[num][wh^1]=fa;
    	pre[fa]=num;
    	update(fa);
    	update(num);
    }
    
    void splay(int num) {
    	int top=0;
    	Q[++top]=num;
    	for (int i=num; !isroot(i); i=pre[i])
    		Q[++top]=pre[i];
    	while (top) push(Q[top--]);
    	for (int fa; !isroot(num); rotate(num))
    		if (!isroot(fa=pre[num]))
    			rotate(get(num)==get(fa)? fa:num);
    }
    
    void expose(int num) {
    	int t=0;
    	while (num) {
    		splay(num);
    		ch[num][1]=t;
    		update(num);
    		t=num;
    		num=pre[num];
    	}
    }
    
    void makeroot(int num) {
    	expose(num);
    	splay(num);
    	rev[num]^=1;
    }
    
    void link(int x,int y) {
    	makeroot(x);
    	pre[x]=y;
    }
    
    void cut(int x,int y) {
    	makeroot(x);
    	expose(y);
    	splay(y);
    	ch[y][0]=pre[x]=0;
    }
    
    int way(int x,int y) {
    	makeroot(x);
    	expose(y);
    	splay(y);
    	return pos[y];
    }
    
    int find(int x) {
    	if (fa[x]!=x) fa[x]=find(fa[x]);
    	return fa[x];
    }
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for (int i=1; i<=m; i++)
    		scanf("%d%d%d%d",&po[i].x,&po[i].y,&po[i].a,&po[i].b);
    
    	int ans=1e9;
    	sort(po+1,po+1+m,cmp);
    	for (int i=1; i<=n; i++) fa[i]=i;
    	for (int i=1; i<=m; i++) {
    		int f1=find(po[i].x);
    		int f2=find(po[i].y);
    		if (f1!=f2) {
    			fa[f1]=f2;
    		} 
    		else {
    			int p=way(po[i].x,po[i].y);   
    			if (v[p]>po[i].b) {
    				cut(p,po[p-n].x);
    				cut(p,po[p-n].y);
    			} else {
    				if (find(1)==find(n))
    					ans=min(ans,v[way(1,n)]+po[i].a);
    				continue;
    			}
    		}
    		v[i+n]=po[i].b;
    		pos[i+n]=i+n;
    		link(po[i].x,n+i);
    		link(po[i].y,n+i);
    		if (find(1)==find(n))
    		{
    			int p=way(1,n);
    			ans=min(ans,v[p]+po[i].a);
    		}
    	}
    
    	if (ans==1e9) 
    	  printf("-1");
    	else 
    	  printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    centos安装MySQL5.7
    centos搭建ftp服务器的方法
    centos 7 卸载 mariadb 的正确命令
    MySQL5.7关于密码二三事
    第四次:渗透练习,xss学习
    第三次靶场练习:通过抓包,绕过内部限制
    第二次靶场练习:cookie注入
    第一次靶场练习:SQL注入(1)
    Linux用户和组管理
    Linux基础命令(三)
  • 原文地址:https://www.cnblogs.com/akoasm/p/9419370.html
Copyright © 2011-2022 走看看