BZOJ3669: [Noi2014]魔法森林

n<=50000,m<=100000的图上,路径有属性Ai和Bi,问从1到n的路径中(Ai的最大值+Bi的最大值)的最小值。

双属性图论题,常用套路--定一动二。比如说这里可以先按A从小到大排序,然后依次加入图中来考虑怎么计算B。

方法一:哦,最大值最小,那不是最小生成树吗?会加边的图,那不是LCT维护最小生成树吗?

  1 //#include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 //#include<time.h>
  5 //#include<math.h>
  6 //#include<set>
  7 //#include<queue>
  8 //#include<bitset>
  9 //#include<vector>
 10 #include<algorithm>
 11 #include<stdlib.h>
 12 using namespace std;
 13 
 14 #define LL long long
 15 LL qread()
 16 {
 17     char c; LL s=0; int f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
 18     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
 19 }
 20 
 21 //Pay attention to '-' , LL and double of qread!!!!
 22 
 23 int n,m;
 24 #define maxn 150011
 25 struct LCT
 26 {
 27     struct Node{int son[2],fa,v,Max,maxid; bool rev;}a[maxn];
 28     int n;
 29     void clear(int N) {n=N; a[0].Max=a[0].v=-0x3f3f3f3f;}
 30     void up(int x)
 31     {
 32         if (!x) return;
 33         Node &b=a[x],&c=a[a[x].son[0]],&d=a[a[x].son[1]];
 34         if (b.v>=c.Max && b.v>=d.Max) {b.Max=b.v; b.maxid=x;}
 35         else if (c.Max>=b.v && c.Max>=d.Max) {b.Max=c.Max; b.maxid=c.maxid;}
 36         else {b.Max=d.Max; b.maxid=d.maxid;}
 37     }
 38     void revsingle(int x) {if (!x) return; a[x].rev^=1; swap(a[x].son[0],a[x].son[1]);}
 39     void down(int x) {if (a[x].rev) {revsingle(a[x].son[0]); revsingle(a[x].son[1]); a[x].rev=0;} }
 40     bool isroot(int x) {return !a[x].fa || (x!=a[a[x].fa].son[0] && x!=a[a[x].fa].son[1]);}
 41     void rotate(int x)
 42     {
 43         int y=a[x].fa,z=a[y].fa;
 44         bool w=(x==a[y].son[0]);
 45         a[x].fa=z;
 46         if (!isroot(y)) a[z].son[y==a[z].son[1]]=x;
 47         a[y].son[w^1]=a[x].son[w];
 48         if (a[x].son[w]) a[a[x].son[w]].fa=y;
 49         a[x].son[w]=y;
 50         a[y].fa=x;
 51         up(y); up(z);
 52     }
 53     int sta[maxn],top;
 54     void download(int x)
 55     {
 56         int i=x; while (!isroot(i)) sta[++top]=i,i=a[i].fa; sta[++top]=i;
 57         for (;top;top--) down(sta[top]);
 58     }
 59     void splay(int x)
 60     {
 61         if (!x) return;
 62         download(x);
 63         while (!isroot(x))
 64         {
 65             int y=a[x].fa,z=a[y].fa;
 66             if (!isroot(y)) {if ((x==a[y].son[0])^(y==a[z].son[0])) rotate(x); else rotate(y);}
 67             rotate(x);
 68         }
 69         up(x);
 70     }
 71     void access(int x) {int y=0,z=x; while (x) {splay(x); a[x].son[1]=y; up(x); y=x; x=a[x].fa;} splay(z);}
 72     void reset(int x) {access(x); revsingle(x);}
 73     
 74     void link(int x,int y) {reset(x); a[x].fa=y;}
 75     void cut(int x,int y)
 76     {reset(x); access(y); a[x].fa=a[y].son[0]=0; up(y);}
 77     bool con(int x,int y) {reset(x); while (y) {if (y==x) return 1; y=a[y].fa;} return 0;}
 78     int qmax(int x,int y) {reset(x); access(y); return a[y].maxid;}
 79     
 80 //    void test()
 81 //    {
 82 //        for (int i=1;i<=n;i++) cout<<i<<" fa"<<a[i].fa<<" son0 "<<a[i].son[0]<<" son1 "<<a[i].son[1]
 83 //        <<" v"<<a[i].v<<" Max"<<a[i].Max<<" maxid"<<a[i].maxid<<endl;
 84 //    }
 85 }t;
 86 
 87 struct EE{int x,y,a,b; bool operator < (const EE &b) const {return a<b.a;} }ee[maxn];
 88 int main()
 89 {
 90     n=qread(); m=qread();
 91     for (int i=1;i<=m;i++) {ee[i].x=qread(); ee[i].y=qread(); ee[i].a=qread(); ee[i].b=qread();}
 92     sort(ee+1,ee+1+m);
 93     
 94     int ans=0x3f3f3f3f;
 95     t.clear(n+m);
 96     for (int i=1;i<=n;i++) t.a[i].v=-0x3f3f3f3f,t.a[i].Max=-0x3f3f3f3f,t.a[i].maxid=i;
 97     for (int i=n+1;i<=n+m;i++) t.a[i].v=ee[i-n].b,t.a[i].Max=t.a[i].v,t.a[i].maxid=i;
 98     for (int i=1;i<=m;i++)
 99     {
100         if (t.con(ee[i].x,ee[i].y))
101         {
102             int z=t.qmax(ee[i].x,ee[i].y);
103             if (t.a[z].v>t.a[i+n].v)
104             {
105                 t.cut(ee[z-n].x,z);
106                 t.cut(ee[z-n].y,z);
107                 t.link(ee[i].x,i+n);
108                 t.link(ee[i].y,i+n);
109             }
110         }
111         else {t.link(ee[i].x,i+n); t.link(ee[i].y,i+n); }
112         if (t.con(1,n)) ans=min(ans,ee[i].a+t.a[t.qmax(1,n)].v);
113     }
114     printf("%d
",ans==0x3f3f3f3f?-1:ans);
115     return 0;
116 }
View Code

好久没写了,这次写起来居然这么顺这么短,有点屌。

方法二:LCT学傻了系列,可以先考虑一个暴力:每次加完边之后做一次最短路。不过加了一条边之后,所有导致每个点的答案被更新的根本原因,来自于这条边两端的点的互相更新。也就是说,每加一条边后,前面图的大部分信息是不用算的,就看一下这条边两端的点能否更新彼此,能的话把被更新的点加入队列再跑最短路就OK。复杂度??玄学,反正比LCT快,好写!

 1 #include<string.h>
 2 #include<stdlib.h>
 3 #include<stdio.h>
 4 #include<math.h>
 5 //#include<assert.h>
 6 #include<algorithm> 
 7 #include<queue>
 8 //#include<iostream>
 9 //#include<bitset>
10 using namespace std;
11 
12 int n,m;
13 #define maxn 200011
14 #define maxm 200011
15 struct List{int from,to,a,b;}list[maxm];
16 bool cmpa(const List &a,const List &b) {return a.a<b.a;}
17 struct Edge{int to,next,v;}edge[maxm]; int first[maxn],le=2;
18 void in(int x,int y,int v) {Edge &e=edge[le]; e.to=y; e.v=v; e.next=first[x]; first[x]=le++;}
19 void insert(int x,int y,int v) {in(x,y,v); in(y,x,v);}
20 
21 struct qnode
22 {
23     int id,v;
24     bool operator > (const qnode &b) const {return v>b.v;}
25 };
26 priority_queue<qnode,vector<qnode>,greater<qnode> > q;
27 int dis[maxn];
28 
29 void kick(int x,int y,int ev)
30 {
31     if (dis[x]>max(dis[y],ev))
32     {
33         dis[x]=max(dis[y],ev);
34         q.push((qnode){x,dis[x]});
35     }
36 }
37 void dijkstra()
38 {
39     while (!q.empty())
40     {
41         const int now=q.top().id,d=q.top().v; q.pop();
42         if (dis[now]<d) continue;
43         for (int i=first[now];i;i=edge[i].next)
44         {
45             const Edge &e=edge[i];
46             if (dis[e.to]>max(dis[now],e.v))
47             {
48                 dis[e.to]=max(dis[now],e.v);
49                 q.push((qnode){e.to,dis[e.to]});
50             }
51         }
52     }
53 }
54 
55 int main()
56 {
57     scanf("%d%d",&n,&m);
58     for (int i=1;i<=m;i++) scanf("%d%d%d%d",&list[i].from,&list[i].to,&list[i].a,&list[i].b);
59     sort(list+1,list+1+m,cmpa);
60     list[m+1].a=0x3f3f3f3f;
61     for (int i=1;i<=n;i++) dis[i]=0x3f3f3f3f;
62     dis[1]=0; int ans=0x3f3f3f3f;
63     for (int i=1,j=1;i<=m;i++) if (list[i].a!=list[i+1].a)
64     {
65         for (;j<=i;j++)
66         {
67             insert(list[j].from,list[j].to,list[j].b);
68             kick(list[j].from,list[j].to,list[j].b);
69             kick(list[j].to,list[j].from,list[j].b);
70         }
71         dijkstra();
72         ans=min(ans,list[i].a+dis[n]);
73     }
74     if (ans==0x3f3f3f3f) puts("-1");
75     else printf("%d
",ans);
76     return 0;
77 }
View Code
原文地址:https://www.cnblogs.com/Blue233333/p/8294897.html