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) 编辑 收藏 举报