[bzoj3664][Noi2014]魔法森林 Link-Cut-Tree 并查集
来源:互联网 发布:jvm怎么看java的机械码 编辑:程序博客网 时间:2024/04/26 21:11
3669: [Noi2014]膜法森林
Time Limit: 30 Sec Memory Limit: 512 MB[Submit][Status][Discuss]
Description
为了得到人生的经验,小E同学下定决心去拜访住在膜法森林中的长者。膜法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M。初始时小E同学在号节点1,长者则住在号节点N。小E需要通过这一片膜法森林,才能够拜访到长者。
膜法森林中有一些想搞大新闻的香港记者暗中观察。每当有人经过一条边的时候,这条边上的香港记者就会对其发起攻击。幸运的是,在号节点住着两种蛤:A型蛤与B型蛤。小E可以借助它们的力量,达到自己的目的。
只要小E带上足够多的蛤,香港记者们就不会发起攻击了。具体来说,无向图中的每一条边Ei包含两个权值Ai与Bi。若身上携带的A型蛤个数不少于Ai,且B型蛤个数不少于Bi,这条边上的香港记者就不会对通过这条边的人发起攻击。当且仅当通过这片膜法森林的过程中没有任意一条边的香港记者向小E发起攻击,他才能成功找到长者。
由于携带蛤是一件非常麻烦的事,小E想要知道,要能够成功拜访到长者,最少需要携带蛤的总个数。蛤的总个数为A型蛤的个数与B型蛤的个数之和。
Input
第1行包含两个整数N,M,表示无向图共有N个节点,M条边。 接下来M行,第行包含4个正整数Xi,Yi,Ai,Bi,描述第i条无向边。其中Xi与Yi为该边两个端点的标号,Ai与Bi的含义如题所述。 注意数据中可能包含重边与自环。
Output
输出一行一个整数:如果小E可以成功拜访到隐士,输出小E最少需要携带的守护精灵的总个数;如果无论如何小E都无法拜访到隐士,输出“-1”(不含引号)。
Sample Input
【输入样例1】
4 5
1 2 19 1
2 3 8 12
2 4 12 15
1 3 17 8
3 4 1 17
【输入样例2】
3 1
1 2 1 1
4 5
1 2 19 1
2 3 8 12
2 4 12 15
1 3 17 8
3 4 1 17
【输入样例2】
3 1
1 2 1 1
Sample Output
【输出样例1】
32
【样例说明1】
如果小E走路径1→2→4,需要携带19+15=34个守护精灵;
如果小E走路径1→3→4,需要携带17+17=34个守护精灵;
如果小E走路径1→2→3→4,需要携带19+17=36个守护精灵;
如果小E走路径1→3→2→4,需要携带17+15=32个守护精灵。
综上所述,小E最少需要携带32个守护精灵。
【输出样例2】
-1
【样例说明2】
小E无法从1号节点到达3号节点,故输出-1。
32
【样例说明1】
如果小E走路径1→2→4,需要携带19+15=34个守护精灵;
如果小E走路径1→3→4,需要携带17+17=34个守护精灵;
如果小E走路径1→2→3→4,需要携带19+17=36个守护精灵;
如果小E走路径1→3→2→4,需要携带17+15=32个守护精灵。
综上所述,小E最少需要携带32个守护精灵。
【输出样例2】
-1
【样例说明2】
小E无法从1号节点到达3号节点,故输出-1。
HINT
2<=n<=50,000
0<=m<=100,000
1<=ai ,bi<=50,000
Source
noi2014有80个人A了这题
正解是LCT,然而SPFA要快得多
类似kruskal的做法
先按A的大小连边
然后每次加点,如果存在一个环,就要减去前面的B值最大的(想一想为什么只管B的值?)
然后如果找到1到n的路径,就更新答案
#include<algorithm>#include<iostream>#include<cstdio>#define inf 1000000000using namespace std;const int N = 200000 + 5;int mx[N],va[N],p[N],fa[N],c[N][2],sta[N],ans=inf,top,n,m;bool rev[N];struct data{int u,v,a,b;}e[N];int find( int x ){ return p[x] == x ? x : p[x] = find(p[x]); }bool cmp( data a, data b ){ return a.a < b.a; }bool isroot( int x ){ return c[fa[x]][0]!=x&&c[fa[x]][1]!=x; }void update( int x ){mx[x] = x;if( va[mx[c[x][1]]] > va[mx[x]] ) mx[x] = mx[c[x][1]];if( va[mx[c[x][0]]] > va[mx[x]] ) mx[x] = mx[c[x][0]];}void pushdown( int x ){if( rev[x] ){swap(c[x][0],c[x][1]);rev[c[x][0]] ^= 1; rev[c[x][1]] ^= 1; rev[x] = 0;}}void rotate( int x ){int y = fa[x], z = fa[y], l, r;l = (c[y][1]==x); r = l^1;if( !isroot(y) ) c[z][y==c[z][1]] = x;fa[x] = z; fa[y] = x; fa[c[x][r]] = y;c[y][l] = c[x][r]; c[x][r] = y;update(y); update(x);}void splay( int x ){sta[++top] = x;for( int i = x; !isroot(i); i = fa[i] ) sta[++top] = fa[i];while( top ) pushdown(sta[top--]);while( !isroot(x) ){int y = fa[x], z = fa[y];if( !isroot(y) ){if( (c[y][0]==x)^(c[z][0]==y) ) rotate(x);else rotate(y);}rotate(x);}}void access( int x ){for( int t = 0; x; t = x, x = fa[x] ){splay(x); c[x][1] = t; update(x);}}void move_to_root( int x ){access(x); splay(x); rev[x] ^= 1;}void link( int x, int y ){move_to_root(x); fa[x] = y;}void cut( int x, int y ){move_to_root(x); access(y); splay(y); fa[x] = c[y][0] = 0;}int query( int x, int y ){move_to_root(x); access(y); splay(y); return mx[y];}int main(){scanf("%d%d", &n, &m);for( int i = 1; i <= m; i++ ) scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].a, &e[i].b);for( int i = 1; i <= n; i++ ) p[i] = i;sort(e+1,e+m+1,cmp);for( int i = 1,u,v,a,b,c; i <= m; i++ ){u = e[i].u; v = e[i].v; a = e[i].a; b = e[i].b;if( find(u) == find(v) ){c = query(u,v);if( va[c] > e[i].b ){cut( c, e[c-n].u );cut( c, e[c-n].v );} else continue;} else p[find(u)] = find(v);va[n+i] = e[i].b; mx[n+i] = n+i;link(u,n+i); link(v,n+i);if( find(1) == find(n) ) ans = min( ans, a + va[query(1,n)]);}if( ans == inf ){ printf("-1"); return 0; }printf("%d", ans);return 0;}这是lemonoil的SPFA,快多了,还在第二页,具体没有研究过
放在这里存一下
#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<set>#include<queue>#include<algorithm>#include<vector>#include<cstdlib>#include<cmath>#include<ctime>#include<stack>#define rez(i,x,y) for(int i=x;i>=y;i--)#define res(i,x,y) for(int i=x;i<=y;i++)#define INF 2100000000#define ll long long#define M 50500#define clr(x) memset(x,0,sizeof(x)) using namespace std;struct node{ int to,f,next; }table[M<<2];int head[M],tot; struct edges{ int x,y,a,b; bool operator < (const edges &rhs)const{ return a< rhs.a ; } }e[M<<1];int n,m,ans=0x3f3f3f3f,f[M],heap[M],pos[M],top; void push_up(int x){ int t=pos[x]; while(t>1&&f[heap[t]]<f[heap[t>>1]]) swap(heap[t],heap[t>>1]),swap(pos[heap[t]],pos[heap[t>>1]]),t>>=1; } void insert(int x){ heap[++top]=x; pos[x]=top; push_up(x); } void pop(){ pos[heap[1]]=0; heap[1]=heap[top]; heap[top--]=0; pos[heap[1]]=1; int t=2; while(t<=top){ if(t<top&&f[heap[t]]>f[heap[t+1]])t++; if(f[heap[t]]<f[heap[t>>1]]) swap(heap[t],heap[t>>1]),swap(pos[heap[t]],pos[heap[t>>1]]),t<<=1; else break; } } void SPFA(){ while(top){ int x=heap[1];pop(); for(int i=head[x];i;i=table[i].next) if(f[table[i].to]>max(f[x],table[i].f)){ f[table[i].to]=max(f[x],table[i].f); if(!pos[table[i].to]) insert(table[i].to); else push_up(table[i].to); } } } void add(int x,int y,int z){ table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; }inline void readin(int &x){ static char ch; do ch=getchar();while(ch<'0'||ch>'9'); while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar(); } int main(){ readin(n),readin(m); for(int i=1;i<=m;i++) readin(e[i].x),readin(e[i].y),readin(e[i].a),readin(e[i].b); sort(e+1,e+m+1); memset(f,0x3f,sizeof(f)); f[1]=0; for(int i=1;i<=m;i++){ add(e[i].x,e[i].y,e[i].b); add(e[i].y,e[i].x,e[i].b); if(f[e[i].x]>f[e[i].y]) swap(e[i].x,e[i].y); if(max(f[e[i].x],e[i].b)<f[e[i].y]) f[e[i].y]=max(f[e[i].x],e[i].b),insert(e[i].y); if(e[i].a!=e[i+1].a)SPFA(); ans=min(ans,e[i].a+f[n]); } if(ans==0x3f3f3f3f)cout<<-1<<endl; else cout<<ans<<endl; return 0; }
阅读全文
1 0
- [bzoj3664][Noi2014]魔法森林 Link-Cut-Tree 并查集
- [Noi2014]魔法森林 (Link Cut Tree)
- 【BZOJ3669】[Noi2014]魔法森林【Link-Cut Tree】【最小生成树】
- bzoj 3669: [Noi2014]魔法森林 link cut tree
- 【BZOJ3669】【Noi2014】魔法森林(Link-Cut Tree)
- link cut tree 学习小结【NOI2014】魔法森林
- BZOJ-3669 魔法森林 Link-Cut-Tree
- [BZOJ3669][Noi2014]魔法森林(并查集+LCT)
- [BZOJ3669]-[Noi2014]魔法森林-LCT+并查集
- luoguP2387 [NOI2014]魔法森林(LCT+并查集)
- [BZOJ 3669][NOI 2014]魔法森林(Link-Cut Tree)
- 【并查集+LCT维护生成树】BZOJ3669(Noi2014)[魔法森林]题解
- BZOJ 2959 长跑 Link-Cut-Tree+并查集
- 【bzoj3669】魔法森林 LCT+并查集
- BZOJ3669 [Noi2014]魔法森林
- 【NOI2014】魔法森林
- bzoj3669: [Noi2014]魔法森林
- [BZOJ3669][Noi2014]魔法森林
- 提高网站访问速度的34条军规(1)
- 计算机进制
- 工单系列2 ---- MyBatis 报错 there is no getter for property named “xxx” in "class xxx"
- 串口UART的封装函数
- .net开发windows服务小结
- [bzoj3664][Noi2014]魔法森林 Link-Cut-Tree 并查集
- 块级标签与内联标签
- java输出1000内的完数
- python 判断文件是否存在以及
- Servlet的调用和生命周期
- hdu 1016 Prime Ring Problem
- Python 读取csv的某行
- REST开发笔记
- SSM系统架构