山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 2959 长跑(LCT+BCC+并查集)

 

【题目链接】

 

    http://www.lydsy.com/JudgeOnline/problem.php?id=2959

 

【题意】

 

    n个点,提供操作:连边,修改点权,查询自定义边的方向后起点a终点b能经过的最大点权和。

 

【思路】

 

    对于一个边的双连通分量,显然可以将权值全部获得。

    如果没有连边操作,我们只需要将一个bcc缩点后求得a->b路径上的点权和即可。

    加上连边后,使用并查集代表一个bcc,如果u,v之间不连通直接连边,如果已经连通则构成一个bcc,使用并查集将LCT的所有节点合并。

    注意缩点后以并查集的代表元为该点,Access上找父亲的时候应该用父亲的bcc代表元。

 

【代码】

 

  1 #include<set>
  2 #include<cmath>
  3 #include<queue>
  4 #include<vector>
  5 #include<cstdio>
  6 #include<cstring>
  7 #include<iostream>
  8 #include<algorithm>
  9 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 10 using namespace std;
 11 
 12 typedef long long ll;
 13 const int N = 3e5+10;
 14 
 15 ll read() {
 16     char c=getchar();
 17     ll f=1,x=0;
 18     while(!isdigit(c)) {
 19         if(c=='-') f=-1; c=getchar();
 20     }
 21     while(isdigit(c))
 22         x=x*10+c-'0',c=getchar();
 23     return x*f;
 24 }
 25 
 26 struct UFS {
 27     int p[N];
 28     int ifind(int x) {
 29         if(p[x]==0||x==p[x]) return p[x]=x;
 30         return p[x]=ifind(p[x]); 
 31     }
 32     void iunion(int x,int y) {
 33         x=ifind(x),y=ifind(y);
 34         if(x!=y) p[x]=y;
 35     }
 36 } bcc,S;
 37 
 38 namespace LCT {
 39 
 40     struct Node {
 41         Node *ch[2],*fa;
 42         int v,rev,sum;
 43         Node() {}
 44         Node(int x) ;
 45         void reverse() {
 46             rev^=1;
 47             swap(ch[0],ch[1]);
 48         }
 49         void up_push() {
 50             if(fa->ch[0]==this||fa->ch[1]==this) 
 51                 fa->up_push();
 52             if(rev) {
 53                 ch[0]->reverse();
 54                 ch[1]->reverse();
 55                 rev=0;
 56             }
 57         }
 58         void maintain() {
 59             sum=v+ch[0]->sum+ch[1]->sum;
 60         }
 61     } T[N],*null=&T[0];
 62     Node::Node(int x) {
 63         rev=0;
 64         v=sum=x;
 65         ch[0]=ch[1]=fa=null;
 66     }
 67     
 68     void rot(Node* o,int d) {
 69         Node *p=o->fa;
 70         p->ch[d]=o->ch[d^1];
 71         o->ch[d^1]->fa=p;
 72         o->ch[d^1]=p;
 73         o->fa=p->fa;
 74         if(p==p->fa->ch[0])
 75             p->fa->ch[0]=o;
 76         else if(p==p->fa->ch[1])
 77             p->fa->ch[1]=o;
 78         p->fa=o;
 79         p->maintain();
 80     }
 81     void splay(Node *o) {
 82         o->up_push();
 83         Node *nf,*nff;
 84         while(o->fa->ch[0]==o||o->fa->ch[1]==o) {
 85             nf=o->fa,nff=nf->fa;
 86             if(o==nf->ch[0]) {
 87                 if(nf==nff->ch[0]) rot(nf,0);
 88                 rot(o,0);
 89             } else {
 90                 if(nf==nff->ch[1]) rot(nf,1);
 91                 rot(o,1);
 92             }
 93         }
 94         o->maintain();
 95     }
 96     void Access(Node *o) {
 97         Node *son=null;
 98         while(o!=null) {
 99             splay(o);
100             o->ch[1]=son;
101             o->maintain();
102             o->fa=&T[bcc.ifind(o->fa-T)];
103             son=o; o=o->fa;
104         }
105     }
106     void evert(Node *o) {
107         Access(o); 
108         splay(o);
109         o->reverse();
110     }
111     void Link(Node *u, Node *v) {
112         evert(u);
113         u->fa=v;
114     }
115 
116 }
117 
118 using namespace LCT;
119 
120 int n,m,a[N];
121 
122 void merge(Node* &u,Node* v) 
123 {
124     if(u==null) return ;
125     v->v+=u->v;
126     bcc.iunion(u-T,v-T);
127     merge(u->ch[0],v);
128     merge(u->ch[1],v);
129     u=null;
130 }
131 
132 int main()
133 {
134     n=read(),m=read();
135     FOR(i,1,n) {
136         a[i]=read(); T[i]=Node(a[i]);
137     }
138     int op,u,v;
139     FOR(i,1,m) {
140         op=read(),u=read(),v=read();
141         if(op==1) {
142             u=bcc.ifind(u),v=bcc.ifind(v);
143             if(u==v) continue;
144             if(S.ifind(u)!=S.ifind(v))
145                 Link(&T[u],&T[v]),
146                 S.iunion(u,v);
147             else {
148                 evert(&T[u]);
149                 Access(&T[v]),splay(&T[v]);
150                 merge(T[v].ch[0],&T[v]);
151                 merge(T[v].ch[1],&T[v]);
152                 T[v].maintain();
153             }
154         } else 
155         if(op==2) {
156             splay(&T[bcc.ifind(u)]);
157             T[bcc.ifind(u)].v+=v-a[u];
158             T[bcc.ifind(u)].maintain();
159             a[u]=v;
160         } else {
161             u=bcc.ifind(u),v=bcc.ifind(v);
162             if(S.ifind(u)!=S.ifind(v)) puts("-1");
163             else {
164                 evert(&T[u]);
165                 Access(&T[v]),splay(&T[v]);
166                 printf("%d\n",T[v].sum);
167             }
168         }
169     }
170     return 0;
171 }

 

 

Q:打码的最怕什么

A:手残和眼瞎。

真不巧,我两样都是

 

posted on 2016-03-26 18:29  hahalidaxin  阅读(502)  评论(0编辑  收藏  举报