• 【BZOJ 3669】【NOI 2014】魔法森林 LCT+枚举边


    $LCT+枚举$ 复习一下$LCT$模板。

    先以$Ai$为关键字$sort$,然后$Ai$从小到大枚举每条边,看能否构成环,构不成则加边,构成则判断,判断过了就切断$Bi$最大的边。

    我的边是编号为$i+n$的点,忘了这点调了好久$QAQ$ $sosad$

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 150003
    #define read(x) x=getint()
    using namespace std;
    inline int getint() {int k = 0, fh = 1; char c = getchar();	for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh;}
    struct nodeE {int a, b, x, y;} E[N];
    struct node *null;
    struct node {
    	node *ch[2], *fa;
    	int d, pos;
    	short rev;
    	bool pl() {return fa->ch[1] == this;}
    	bool check() {return fa == null || (fa->ch[0] != this && fa->ch[1] != this);}
    	void push() {if (rev) {rev = 0; swap(ch[0], ch[1]); ch[0]->rev ^= 1; ch[1]->rev ^= 1;}}
    	void count() {
    		pos = d;
    		if (E[ch[0]->pos].b > E[pos].b) pos = ch[0]->pos;
    		if (E[ch[1]->pos].b > E[pos].b) pos = ch[1]->pos;
    	}
    	void setc(node *r, bool c) {ch[c] = r; r->fa = this;}
    } *rt[N];
    node pool[N];
    int n, m, tot = 0;
    namespace LCT {
    	int ans = 0x7fffffff;
    	bool cmp(nodeE X, nodeE Y) {return X.a < Y.a;}
    	node *newnode(int num = 0) {
    		node *t = &pool[++tot];
    		t->ch[0] = t->ch[1] = t->fa = null;
    		t->d = t->pos = num; t->rev = 0;
    		return t;
    	}
    	void Build() {
    		null = &pool[0];
    		null->ch[0] = null->ch[1] = null->fa = null;
    		null->d = null->pos = null->rev = 0;
    		read(n); read(m);
    		for(int i = 1; i <= m; ++i)
    			{read(E[i].x); read(E[i].y); read(E[i].a); read(E[i].b);}
    		sort(E + 1, E + m + 1, cmp);
    		for(int i = 1; i <= n; ++i)
    			rt[i] = newnode();
    		for(int i = 1; i <= m; ++i)
    			rt[n + i] = newnode(i);
    		E[0].b = 0;
    	}
    	void rotate(node *r) {
    		node *f = r->fa;
    		bool c = r->pl();
    		if (f->check()) r->fa = f->fa;
    		else f->fa->setc(r, f->pl());
    		f->setc(r->ch[!c], c);
    		r->setc(f, !c);
    		f->count();
    	}
    	void update(node *r) {if (!r->check()) update(r->fa); r->push();}
    	void splay(node *r) {
    		update(r);
    		for(; !r->check(); rotate(r))
    			if (!r->fa->check()) rotate(r->pl() == r->fa->pl() ? r->fa : r);
    		r->count();
    	}
    	node *access(node *r) {node *y = null;	for(; r != null; y = r, r = r->fa) {splay(r); r->ch[1] = y;} return y;}
    	void changert(node *r) {access(r)->rev ^= 1; splay(r);}
    	void link(node *r, node *t) {changert(r); r->fa = t;}
    	void cut(node *r, node *t) {changert(r); access(t); splay(t); t->ch[0]->fa = null; t->ch[0] = null;}
    	node *findrt(node *r) {access(r); splay(r); while(r->ch[0] != null) r = r->ch[0]; return r;}
    	int ask(node *r, node *t) {changert(r); access(t); splay(t); return t->pos;}
    	void work(int u, int v, int edge) {
    		if (findrt(rt[u]) == findrt(rt[v])) {
    			int k = ask(rt[u], rt[v]);
    			if (E[k].b > E[edge - n].b) {
    				cut(rt[u], rt[k + n]);
    				cut(rt[v], rt[k + n]);
    				link(rt[u], rt[edge]);
    				link(rt[v], rt[edge]);
    			}
    		} else {
    			link(rt[u], rt[edge]);
    			link(rt[v], rt[edge]);
    		}
    		if (findrt(rt[1]) == findrt(rt[n]))
    			ans = min(ans, E[edge - n].a + E[ask(rt[1], rt[n])].b);
    	}
    	void AC() {printf("%d
    ", ans == 0x7fffffff ? -1 : ans);}
    }
    
    int main() {
    	LCT::Build();
    	for(int i = 1; i <= m ;++i)
    		LCT::work(E[i].x, E[i].y, i + n);
    	LCT::AC();
    	return 0;
    }
    

    我的代码就是一堵墙,让$300$行的$LinkCutTree$在压行大法前颤抖吧~~~

  • 相关阅读:
    Crowdsec:一款面向Linux的现代化协作式大型多人防火墙
    Linux文件操作:利用C语言删除某个目录下的文件
    GitHub 长期被中国人“霸榜”?看完这些榜单,这又是什么新姿势?
    英语不好学不好编程?程序员记忆单词专属诀窍,效果简直要逆天
    谁说女生不适合当程序员?世界第一位程序员,就是女性!
    C语言丨一篇文章带你认识递归与迭代
    C语言进阶丨(七)数组的基本概念和初始化【1】
    赔97.6万元!腾讯一程序员违反竞业协议,三年白干了!
    雪夜思绪
    算法复习(2)递归
  • 原文地址:https://www.cnblogs.com/abclzr/p/5350445.html
Copyright © 2020-2023  润新知