BZOJ 3669: [Noi2014]魔法森林
来源:互联网 发布:农村淘宝咨询电话 编辑:程序博客网 时间:2024/05/17 16:00
题目
BZOJ 3669: [Noi2014]魔法森林
题解
感觉收获就是get了一种除了Kruskal和prim之外的最小生成树算法。
理论复杂度貌似是mlogn,不过常数巨大堪比一个log(此句话引用自某论文)。
陈年老题谁都会做,我没做出来qwq。边权按a排序之后做b的最小生成树。对于一条连接(u,v)的边,如果uv不连通那么连起来,否则找u->v最大的边权,然后切掉,把当前边加进去,当1,n联通的时候可以更新答案(我tm还zz的写成了弄出来一棵生成树的时候才有答案,好像也有很多人和我一样(雾))。边权不好维护,把边抽象成点,用点权维护。
然后就是splay维护最大值和最大值出现位置了。easy。感觉lct的板子总是哪里要打错然后调很久233,。不过调的越来越熟练了。自己发明了一套成体系的调试方法,对于指针党简直是太棒了。
代码
//QWsin#include<map>#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn=200000+10;const int maxm=100000+10;map<int,int>id;int n,m;struct Edge{ int u,v,a,b; inline void input(){scanf("%d%d%d%d",&u,&v,&a,&b);} inline bool operator < (const Edge &rhs)const{ return a<rhs.a||(a==rhs.a&&b<rhs.b); }} e[maxm];struct Node{ int v,pos,mx,posx,rev; Node *ch[2],*fa; Node(){v=pos=mx=posx=rev=0;ch[0]=ch[1]=fa=NULL;} Node(int v,int pos):v(v),pos(pos){mx=v,posx=pos;rev=0;ch[0]=ch[1]=fa=NULL;} inline void push(){ if(rev){ swap(ch[0],ch[1]); if(ch[0]) ch[0]->rev^=1; if(ch[1]) ch[1]->rev^=1; rev=0; } } inline void up() { mx=v,posx=pos; if(ch[0] && ch[0]->mx > mx) mx=ch[0]->mx,posx=ch[0]->posx; if(ch[1] && ch[1]->mx > mx) mx=ch[1]->mx,posx=ch[1]->posx; }; inline void out(){ if(!this) {puts("NULL");return ;} printf("%d:\n",id[(int)this]); printf(" ch[0]=%d\n",id[(int)ch[0]]); printf(" ch[1]=%d\n",id[(int)ch[1]]); printf(" fa=%d\n",id[(int)fa]); printf(" val=%d\n",v); printf(" mx=%d\n",mx); printf(" posx=%d\n",posx); puts("\n"); }}*tmp[maxn];struct LinkCutTree{ Node *node[maxn]; inline void init() { id[0]=0; for(int i=1; i<=n; ++i) node[i]=new Node(),id[(int)node[i]]=i; for(int i=1; i<=m; ++i) node[n+i]=new Node(e[i].b,i),id[(int)node[n+i]]=n+i; } inline int pd(Node* p){return p->fa->ch[1]==p;} inline int is_root(Node* p){return (!(p->fa))||(p->fa->ch[0]!=p&&p->fa->ch[1]!=p);} inline void rotate(Node* p) { int c=pd(p)^1; Node *t=p->fa; t->ch[c^1]=p->ch[c]; if(p->ch[c]) p->ch[c]->fa=t; p->fa=t->fa; if(!is_root(t)) p->fa->ch[pd(t)]=p; t->fa=p;p->ch[c]=t;t->up();p->up();// p->out(); } inline void splay(Node *p) { int top=0; for(Node* t=p;; t=t->fa) { tmp[++top]=t; if(is_root(t)) break; } for(; top>=1; --top) tmp[top]->push(); for(; !is_root(p); rotate(p)) if(!is_root(p->fa)) rotate(pd(p)==pd(p->fa) ? p->fa:p); } inline void access(Node* p) {// p->out(); for(Node* pre=NULL; p ; pre=p,p=p->fa){ splay(p),p->ch[1]=pre,p->up();// pre->out();p->out(); } } inline void make_root(Node* p){access(p);splay(p);p->rev=1;} inline void link(Node* a,Node *b){// a->out();b->out(); make_root(a);a->fa=b;// a->out();b->out(); } inline void cut(Node* a,Node *b){ make_root(a);access(b);splay(b); a->fa=b->ch[1]=NULL;b->up(); } inline void link(int i){ link(node[e[i].u],node[n+i]); link(node[n+i],node[e[i].v]); } inline void cut(int i){ cut(node[e[i].u],node[i+n]); cut(node[i+n],node[e[i].v]); } inline int getmx(int u,int v,int &id) //u->v路径最大值 { make_root(node[v]); access(node[u]); splay(node[u]); id=node[u]->posx; return node[u]->mx; } //在u->v路径上找到最大的决定要不要换 inline void find_mx(int i) { int id,val=getmx(e[i].u,e[i].v,id); if(val > e[i].b){cut(id);link(i);} }} lct;inline void init_data(){ cin>>n>>m; for(int i=1; i<=m; ++i) e[i].input(); sort(e+1,e+m+1);}int p[maxn];int findset(int x){return p[x]==x?x:p[x]=findset(p[x]);}inline void solve(){ for(int i=1; i<=n; ++i) p[i]=i; lct.init(); int ans=1<<30,cnt=n,bin; for(int i=1; i<=m; ++i) { if(e[i].a > ans) break; int u=e[i].u,v=e[i].v; u=findset(u); v=findset(v); if(u!=v){lct.link(i); p[u]=v; --cnt;} else lct.find_mx(i); if(findset(1)==findset(n)) ans=min(ans,e[i].a+lct.getmx(1,n,bin)); } if(findset(1)!=findset(n)) puts("-1"); else cout<<ans<<endl;}int main(){ init_data(); solve(); return 0;}
阅读全文
0 0
- bzoj 3669: [Noi2014]魔法森林
- bzoj 3669: [Noi2014]魔法森林
- bzoj 3669: [Noi2014]魔法森林
- BZOJ 3669: [Noi2014]魔法森林
- BZOJ 3669: [Noi2014]魔法森林
- bzoj 3669: [Noi2014]魔法森林
- BZOJ 3669 NOI2014 魔法森林 SPFA
- BZOJ 3669 [Noi2014]魔法森林 LCT
- 【LCT】BZOJ 3669: [Noi2014]魔法森林
- bzoj 3669 NOI2014 魔法森林 [LCT]
- [BZOJ 3669][Noi2014]魔法森林:SPFA
- BZOJ 3669 [Noi2014]魔法森林 LCT
- BZOJ 3669: [Noi2014]魔法森林 LCT
- BZOJ 3669 [Noi2014]魔法森林 Kruskal+LCT
- [BZOJ]3669: [Noi2014]魔法森林 lct
- BZOJ 3669 . JZOJ 3754. 【NOI2014】魔法森林
- 3669: [Noi2014]魔法森林
- 3669: [Noi2014]魔法森林
- 用 cctld工具创建带有国家代码的IP地址表
- UART学习笔记
- 【顶部导航】Android自定义指示器实现顶部导航(三角形,线,bitmap指示器),Fragment与ViewPager的组合。
- C语言 贪吃蛇实现(不闪屏)
- Android kotlin和java反编译后的smali 有什么区别?
- BZOJ 3669: [Noi2014]魔法森林
- oracle常用命令--创建表之create命令(包含主键约束,外键约束)
- Android instrumentation test
- shell中执行一个字符串命令的方法
- enq: TX
- dubbo-如何搭建maven项目,并实现Dubbo分布式服务管理
- 云数据中心安全设计要点
- leetcode-4 Median of Two Sorted Arrays
- URLEncoder与URLDecoder