【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=2816
【题意】
给定一个无向图,满足条件:从一个节点出发的同色边不超过2条,且不存在同色环。要求提供修改节点权值,修改边的颜色,查询同色边c构成的图中u->v路径上节点的最大权值。
【思路】
根据满足的条件,可以判断同色的图构成了若干条一条链。
考虑使用splay维护这些链:
对于每个图上的点建C个splay结点。这里需要splay提供将结点u旋转到根的操作,所以需要维护一个fa指针指向父亲,直接定位到结点u地址,先把该点到root路径上的所有标记下传,然后将u从下向上旋转至根。
对于点修改:将u的所有颜色的结点修改。
对于边修改:设oldc为原来边的颜色w为新颜色,uv为边的端点。将oldc颜色的u,v之间断开,然后把w颜色的uv连接。这里用到split和merge的操作。考虑merge,先将u,v splay至根,这时候一定满足u,v必有一个儿子为空(否则提前输出错误),如果出现u,v是相同儿子为空的情况,我们需要反转u的序列然后连接,所以splay还要维护一个rev的懒标记。
对于查询:将u旋转到根,v旋转到u的一个儿子,假设位于d。u以及v以及v的d^1儿子构成了u..v之间的序列,这里可以加一个ori表示原来该节点代表的值,则答案为max{u->ori,v->ori,v->ch[d^1]->v}。
【代码】
1 #include<map> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 typedef pair<int,int> edge; 15 const int N = 5e4+10; 16 const int M = 5e5+10; 17 18 ll read() { 19 char c=getchar(); 20 ll f=1,x=0; 21 while(!isdigit(c)) { 22 if(c=='-') f=-1; c=getchar(); 23 } 24 while(isdigit(c)) 25 x=x*10+c-'0',c=getchar(); 26 return x*f; 27 } 28 29 struct Edge { 30 int v,w,nxt; 31 }e[M]; 32 int en=1,front[N]; 33 void adde(int u,int v,int w) 34 { 35 e[++en]=(Edge){v,w,front[u]}; front[u]=en; 36 } 37 38 struct Node *null; 39 struct Node { 40 Node *ch[2],*fa; 41 int v,ori,rev; 42 void init(int x) { 43 v=ori=x; rev=0; 44 ch[0]=ch[1]=fa=null; 45 } 46 void maintain() { 47 v=max(ori,max(ch[0]->v,ch[1]->v)); 48 } 49 void pushdown() { 50 if(rev) { 51 swap(ch[0],ch[1]); 52 ch[0]->rev^=1,ch[1]->rev^=1; 53 rev=0; 54 } 55 } 56 }*node[N][20],nodepool[N*20]; 57 58 void rot(Node *o, int d) { 59 Node *k=o->ch[d],*tmp=null; 60 o->ch[d]=k->ch[d^1]; 61 if((tmp=k->ch[d^1])!=null) tmp->fa=o; 62 k->ch[d^1]=o; 63 if((tmp=o->fa)!=null) tmp->ch[tmp->ch[1]==o]=k; 64 o->fa=k; k->fa=tmp; 65 } 66 void up_push(Node* u) { 67 static Node* st[N]; int top=0; 68 while(u!=null) { 69 st[++top]=u; 70 u=u->fa; 71 } 72 while(top) 73 st[top--]->pushdown(); 74 } 75 void splay(Node* u,Node* des=null) { 76 up_push(u); 77 Node *nf,*nff; 78 while(u!=des && (nf=u->fa)!=des) { 79 nff=nf->fa; 80 if(nff==des) rot(nf,nf->ch[1]==u),nf->maintain(); 81 else { 82 int d1=nf->ch[1]==u,d2=nff->ch[1]==nf; 83 if(d1==d2) rot(nff,d2),rot(nf,d1); 84 else rot(nf,d1),rot(nff,d2); 85 nff->maintain(),nf->maintain(); 86 } 87 } 88 u->maintain(); 89 } 90 void reverse(Node* u) { 91 swap(u->ch[0],u->ch[1]); 92 u->ch[0]->rev^=1; 93 u->ch[1]->rev^=1; 94 } 95 void split(Node* u,Node* v) { 96 splay(u); splay(v,u); 97 int d=u->ch[1]==v; 98 u->ch[d]=null,v->fa=null; 99 u->maintain(); 100 } 101 void merge(Node* u,Node* v) { 102 splay(u); splay(v); 103 if(u->ch[1]==null&&v->ch[0]==null) u->ch[1]=v; 104 else if(u->ch[0]==null&&v->ch[1]==null) u->ch[0]=v; 105 else { 106 reverse(u); 107 if(u->ch[0]==null) u->ch[0]=v; 108 else u->ch[1]=v; 109 } 110 v->fa=u; 111 u->maintain(); 112 } 113 114 int n,m,C,K; 115 int col_cnt[N][20],col_vis[N][20],q[N],a[N]; 116 map<pair<int,int>,int> mp; 117 118 Node* build(int l,int r,Node* fa,int* q,int c) { 119 if(r<l) return null; 120 int mid=l+r>>1; 121 Node *u=node[q[mid]][c]; 122 u->init(a[q[mid]]); 123 u->fa=fa; 124 u->ch[0]=build(l,mid-1,u,q,c); 125 u->ch[1]=build(mid+1,r,u,q,c); 126 u->maintain(); 127 return u; 128 } 129 void bfs(int u,int c) { 130 static int q[M],f,r; 131 f=r=0; 132 col_vis[u][c]=1; 133 q[r++]=u; 134 while(f<r) { 135 int u=q[f++]; 136 trav(u,i) if(e[i].w==c&&!col_vis[e[i].v][c]){ 137 col_vis[e[i].v][c]=1; 138 q[r++]=e[i].v; 139 break; 140 } 141 } 142 build(0,r-1,null,q,c); 143 } 144 145 int connect(Node* u,Node* v) { 146 splay(u); splay(v); 147 return u->fa!=null; 148 } 149 int querymax(Node* u,Node* v) { 150 splay(u),splay(v,u); 151 int d=v==u->ch[1]; 152 return max(max(u->ori,v->ori),v->ch[d^1]->v); 153 } 154 155 int main() 156 { 157 //freopen("in.in","r",stdin); 158 //freopen("out.out","w",stdout); 159 null=new Node(); 160 n=read(),m=read(),C=read(),K=read(); 161 FOR(i,1,n) a[i]=read(); 162 FOR(i,1,m) { 163 int u=read(),v=read(),w=read(); 164 w++; 165 adde(u,v,w),adde(v,u,w); 166 col_cnt[u][w]++; 167 col_cnt[v][w]++; 168 if(u>v) swap(u,v); 169 mp[make_pair(u,v)]=w; 170 } 171 FOR(i,1,n) FOR(j,1,C) { 172 node[i][j]=&nodepool[(i-1)*C+j-1]; 173 node[i][j]->init(0); //³õʼ»¯ÄÚ´æ³Ø 174 } 175 FOR(i,1,C) FOR(j,1,n) 176 if(!col_vis[j][i]&&col_cnt[j][i]==1) bfs(j,i); 177 FOR(i,1,K) { 178 int op=read(),x,y,w; 179 if(x>y) swap(x,y); 180 if(op==0) { 181 x=read(),y=read(); 182 a[x]=y; 183 FOR(i,1,C) { 184 splay(node[x][i]); 185 node[x][i]->ori=node[x][i]->v=y; 186 node[x][i]->maintain(); 187 } 188 } else 189 if(op==1) { 190 x=read(),y=read(); 191 if(x>y) swap(x,y); 192 w=read(); w++; 193 if(!mp.count(make_pair(x,y))) puts("No such edge."); 194 else { 195 int old=mp[make_pair(x,y)]; 196 if(old==w) { puts("Success."); continue; } 197 if(col_cnt[x][w]+1>2 || col_cnt[y][w]+1>2) puts("Error 1."); 198 else if(connect(node[x][w],node[y][w])) puts("Error 2."); 199 else { 200 split(node[x][old],node[y][old]); 201 merge(node[x][w],node[y][w]); 202 --col_cnt[x][old]; 203 --col_cnt[y][old]; 204 ++col_cnt[x][w]; 205 ++col_cnt[y][w]; 206 mp[make_pair(x,y)]=w; 207 puts("Success."); 208 } 209 } 210 } else { 211 w=read(); w++; 212 x=read(),y=read(); 213 if(x==y) printf("%d ",a[x]); 214 else if(!connect(node[x][w],node[y][w])) puts("-1"); 215 else printf("%d ",querymax(node[x][w],node[y][w])); 216 } 217 } 218 return 0; 219 }
P.S. 第一次写这种splay,代码借鉴别人的,又涨姿势了 ฅ(๑˙o˙๑)ฅ