bzoj 2816: [ZJOI2012]网络(splay)

【题目链接】

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\n",a[x]);
214             else if(!connect(node[x][w],node[y][w])) puts("-1");
215             else printf("%d\n",querymax(node[x][w],node[y][w]));
216         }
217     }
218     return 0;
219 }

P.S. 第一次写这种splay,代码借鉴别人的,又涨姿势了 ?(?˙o˙?)?

时间: 2024-10-08 16:44:41

bzoj 2816: [ZJOI2012]网络(splay)的相关文章

[ZJOI2012]网络

[ZJOI2012]网络 题目 思路 显然,这是一道lct裸题.因为颜色不多,所以对于每一种颜色的边我们都建一个lct即可.(我这里是用 (颜色×n+点的标号) 表示每一种颜色lct) 操作0 因为我们对于每一种颜色的边都建了一个lct所以,我们对于每一种颜色的边都update一次.(虽然很暴力,但跑得过) 操作1 1.其实对于判断边不存在的情况,我们可以用临接矩阵来存,开一个bool数组10000*10000 128M还是开得下的.这样节约了很多时间(其实是我懒得想其它方法判断). 2.错误1

BZOJ 1588 营业额统计 Splay

主要操作为Splay中插入节点,查找前驱和后继节点. 1: #include <cstdio> 2: #include <iostream> 3: #include <cmath> 4: using namespace std; 5: #define MaxL 100005 6: #define INF 0x7ffffff 7: #define keyTree sp[sp[root].child[1]].child[0] 8:   9: struct SplayTree

AC日记——[ZJOI2012]网络 bzoj 2816

2816 思路: 多个LCT: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 10005 #define ll long long int val[maxn]; struct LinkCutTreeType { int f[maxn],Max[maxn],ch[maxn][2],rev[maxn],sta[maxn],top,cnt[maxn]; void updata(int now) { Max[now]=va

[ZJOI2012][bzoj 2816] 网络 network [LCT]

题目: http://www.lydsy.com/JudgeOnline/problem.php?id=2816 思路: 第一个条件看完暂时还没什么想法 看完第二个,发现每一个颜色都是一个森林 进而想到对于每一个颜色维护LCT 看数据范围,n<=10000, c<=10,可行 对于操作0,把每一个LCT上该店的权值都修改 对于操作1,先检测这条边是否存在,若不存在就No such edge 如果这条边存在,且原来的颜色不同于要修改的颜色的话,就先判断Error 1和Error 2 如果要改的边

[bzoj2816][ZJOI2012]网络(LCT,splay)

传送门 题解 话说以前还真没见过用LCT只维护一条链的……好像除了树点涂色那题…… 先看一下题目规定的两个性质 对于任意节点连出去的边中,相同颜色的边不超过两条. 图中不存在同色的环,同色的环指相同颜色的边构成的环. 很明显了,同一种颜色肯定是由几条链组成的(虽然我根本没有发现) 然后又要查询边权和维护路径……直接上LCT吧 然后颜色数很少啊……每一个颜色开一个LCT好了 更改权值的话在每一个LCT上splay一下 修改颜色的话在原来的LCT中cut,新的LCT中link 查询路径直接split

[题解]bzoj 1861 Book 书架 - Splay

1861: [Zjoi2006]Book 书架 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1396  Solved: 803[Submit][Status][Discuss] Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位

BZOJ 1507 NOI2003 Editor Splay

题目大意: 1.将光标移动到某一位置 2.在光标后插入一段字符串 3.删除光标后的一段字符 4.输出光标后的一段字符 5.光标-- 6.光标++ 和1269很像的一道题,不过弱多了 几个问题需要注意: 1.插入的字符串中间居然会有回车!!没办法了,只能逐个字符进行读入,一旦读到'\n'或者'\r'就重新读入 2.题目描述中说Delete和Get操作后面一定会有足够的字符 纯属放P 连样例都没有足够的字符用来删除 所以删除时要和字符串长度取一个最小值 然后就水水地过去了~ 30%达成 今天是不是可

BZOJ 3931: [CQOI2015]网络吞吐量

3931: [CQOI2015]网络吞吐量 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1555  Solved: 637[Submit][Status][Discuss] Description 路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点.网络中实现路由转发的硬件设备称为路由器.为了使数据包最快的到达目的地,路由器需要选择最优的路径转发数据包.例如在常用的路由算法OSPF(开放式最短路径优先)中

bzoj 3223 文艺平衡树 Splay 打标志

是NOI2003Editor的一个子任务 1 #include <cstdio> 2 #include <vector> 3 #define maxn 100010 4 using namespace std; 5 6 struct Splay { 7 int pre[maxn], son[maxn][2], siz[maxn], rev[maxn], root; 8 9 void update( int nd ) { 10 siz[nd] = siz[son[nd][0]]+si