BZOJ 3669 【NOI 2014】 魔法森林

题意:

  给定一个n个结点,m条边的的无向图,每条边有两个权值ai,bi。 现在从1出发,要到达n,出发时带上任意多的A,B,每次只能沿着ai≤A且bi≤B的边走,问至少要带多少的A,B使得能从1到n。n≤50000,m≤200000。

分析:

  二维参数的一些问题,我们经常用的套路是一维排序,另一维数据结构维护,这道题也可用这种手段解决~

  问题要从简单处入手→ 假如只有一维参数A(先不考虑B)应该怎么办?

    很显然,我们应该用一个Kruskal的思想,因为连通两个点,使最大的边权最小,那么这个最大的边权

    一定存在于最小生成树上。

  可是现在有两位参数→ 我们怎样应用这种思想呢?

    一个思路是,并查集维护连通性,先把边按照A从小到大加入,加入的同时,根据点1和点n间是否连通,

    我们分成两种情况:

    1. 两个点不连通,那么我们直接将枚举的这条边连通。

    2. 如果两个点连通,那我们首先要看这条边是否适合被加入,(假设这条边两端点为x,y)如果想x,y

    两点之间路径上的B最大的边的B都比这条新边的B要小,那它显然不适合被加入,因为在两个参数都更

    劣的情况下,这条边显然是没有任何竞争力的,但如果原路径上B最大的边的B值比新边大,那么我们就

    把B值最大的那条边断掉,并且加入新边。

  如此这般,我们每次加边之后,若点1和点n连通,就用当前枚举到的A值和1-n路径上的最大B值加起来去更新答案。

  以上步骤,需要用并查集维护连通性,并且用LCT维护每条边的B权值,以此来维护两点间路径上的最大B值。

  维护点权的LCT,依然是把“边和权”的形式转化为“边——点权——边”的形式,正常的点权值为零即可!

代码:

  1 #include<bits/stdc++.h>
  2 #define max(a,b,c) max(max(a,b),c)
  3 #define lc(x) t[x][0]
  4 #define rc(x) t[x][1]
  5 using namespace std;
  6 const int N=200005;
  7 struct node{int x,y,a,b;}e[N];
  8 int t[N][2],rev[N],val[N],mx[N],fu[N];
  9 int s[N],tp=0,n,m,k,fa[N];
 10 char readchar(){
 11     static char buf[100000],*l=buf,*r=buf;
 12     if(l==r) r=(l=buf)+fread(buf,1,100000,stdin);
 13     if(l==r) return EOF;return *l++;}
 14 int read(){
 15     int x=0,f=1;char ch=readchar();
 16     while(ch<'0'||ch>'9'){if(ch=='-') f=-f;ch=readchar();}
 17     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=readchar();};
 18     return x*f;
 19 } char pbuf[100000],*pp=pbuf;
 20   void push(const char c) {
 21     if(pp-pbuf==100000) fwrite(pbuf,1,100000,stdout),pp=pbuf;
 22     *pp++=c;
 23 } void write(int x) {
 24     static int sta[35];
 25     int top=0;
 26     do{sta[top++]=x%10,x/=10;}while(x);
 27     while(top) push(sta[--top]+'0');push('\n');
 28 } bool cmp(node u,node v){
 29     return u.a<v.a;
 30 } int get(int x){
 31     return fa[x]==x?x:fa[x]=get(fa[x]);
 32 } void pushup(int x){
 33     int ls=lc(x),rs=rc(x);mx[x]=x;
 34     if(val[mx[ls]]>val[mx[x]]) mx[x]=mx[ls];
 35     if(val[mx[rs]]>val[mx[x]]) mx[x]=mx[rs];
 36 } void pushdown(int x){
 37     int ls=lc(x),rs=rc(x);
 38     if(rev[x]) rev[ls]^=1,rev[rs]^=1,
 39     swap(lc(x),rc(x)),rev[x]=0;return;
 40 } bool pdrt(int x){
 41     return lc(fu[x])!=x&&rc(fu[x])!=x;
 42 } void rotate(int x){
 43     int y=fu[x];int z=fu[y];
 44     int dy=(rc(y)==x),dz=(rc(z)==y);
 45     if(!pdrt(y)) t[z][dz]=x;
 46     t[y][dy]=t[x][dy^1],fu[t[x][dy^1]]=y;
 47     t[x][dy^1]=y;fu[y]=x;fu[x]=z;
 48     pushup(y);
 49 } void splay(int x){
 50     s[++tp]=x;
 51     for(int i=x;!pdrt(i);i=fu[i])
 52     s[++tp]=fu[i];while(tp)
 53     pushdown(s[tp--]);
 54     while(!pdrt(x)){
 55         int y=fu[x];int z=fu[y];if(!pdrt(y))
 56         if(rc(y)==x^rc(z)==y) rotate(x);
 57         else rotate(y);rotate(x);
 58     } pushup(x);
 59 } void access(int x){
 60     for(int i=0;x;x=fu[x])
 61     splay(x),rc(x)=i,i=x;
 62 } void mkrt(int x){
 63     access(x),splay(x);rev[x]^=1;
 64 } int fdrt(int x){
 65     access(x);splay(x);
 66     while(lc(x)) pushdown(x),x=lc(x);
 67     return x;
 68 } void split(int x,int y){
 69     mkrt(x);access(y);splay(y);
 70 } void link(int x,int y){
 71     mkrt(x);if(fdrt(y)!=x) fu[x]=y;
 72 } void cut(int x,int y){
 73     mkrt(x);
 74     if(fdrt(y)==x&&fu[x]==y&&!rc(x))
 75     fu[x]=t[y][0]=0;pushup(y);
 76 } int ask(int x,int y){
 77     split(x,y);return mx[y];
 78 } int main(){ int flg=1,ans=1e9;
 79     n=read();m=read();
 80     for(int i=1,x,y,a,b;i<=m;i++)
 81     x=read(),y=read(),a=read(),b=read(),
 82     e[i]=(node){x,y,a,b};sort(e+1,e+m+1,cmp);
 83     for(int i=1;i<=m;i++)
 84     val[i+n]=e[i].b,mx[i+n]=i+n;
 85     for(int i=1;i<=n;i++) fa[i]=i;
 86     for(int i=1;i<=m;i++){
 87         int x=e[i].x,y=e[i].y;int fx=get(x),fy=get(y);
 88         if(fx!=fy) link(x,i+n),
 89         link(y,i+n),fa[fx]=fy;
 90         else{
 91             int p=ask(x,y);
 92             if(val[p]>e[i].b) cut(e[p-n].x,p),
 93             cut(e[p-n].y,p),link(x,i+n),link(y,i+n);
 94         } if(get(1)==get(n)){
 95             flg=0;int p=ask(1,n);
 96             ans=min(ans,val[p]+e[i].a);
 97         }
 98     } if(flg) push('-'),write(1);else write(ans);
 99     fwrite(pbuf,1,pp-pbuf,stdout); return 0;
100 }
Link-Cut-Tree

 

posted @ 2018-12-21 16:01  杜宇一声  阅读(116)  评论(0编辑  收藏  举报