【题目链接】

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}。

【代码】

 #include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; typedef long long ll;
typedef pair<int,int> edge;
const int N = 5e4+;
const int M = 5e5+; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} struct Edge {
int v,w,nxt;
}e[M];
int en=,front[N];
void adde(int u,int v,int w)
{
e[++en]=(Edge){v,w,front[u]}; front[u]=en;
} struct Node *null;
struct Node {
Node *ch[],*fa;
int v,ori,rev;
void init(int x) {
v=ori=x; rev=;
ch[]=ch[]=fa=null;
}
void maintain() {
v=max(ori,max(ch[]->v,ch[]->v));
}
void pushdown() {
if(rev) {
swap(ch[],ch[]);
ch[]->rev^=,ch[]->rev^=;
rev=;
}
}
}*node[N][],nodepool[N*]; void rot(Node *o, int d) {
Node *k=o->ch[d],*tmp=null;
o->ch[d]=k->ch[d^];
if((tmp=k->ch[d^])!=null) tmp->fa=o;
k->ch[d^]=o;
if((tmp=o->fa)!=null) tmp->ch[tmp->ch[]==o]=k;
o->fa=k; k->fa=tmp;
}
void up_push(Node* u) {
static Node* st[N]; int top=;
while(u!=null) {
st[++top]=u;
u=u->fa;
}
while(top)
st[top--]->pushdown();
}
void splay(Node* u,Node* des=null) {
up_push(u);
Node *nf,*nff;
while(u!=des && (nf=u->fa)!=des) {
nff=nf->fa;
if(nff==des) rot(nf,nf->ch[]==u),nf->maintain();
else {
int d1=nf->ch[]==u,d2=nff->ch[]==nf;
if(d1==d2) rot(nff,d2),rot(nf,d1);
else rot(nf,d1),rot(nff,d2);
nff->maintain(),nf->maintain();
}
}
u->maintain();
}
void reverse(Node* u) {
swap(u->ch[],u->ch[]);
u->ch[]->rev^=;
u->ch[]->rev^=;
}
void split(Node* u,Node* v) {
splay(u); splay(v,u);
int d=u->ch[]==v;
u->ch[d]=null,v->fa=null;
u->maintain();
}
void merge(Node* u,Node* v) {
splay(u); splay(v);
if(u->ch[]==null&&v->ch[]==null) u->ch[]=v;
else if(u->ch[]==null&&v->ch[]==null) u->ch[]=v;
else {
reverse(u);
if(u->ch[]==null) u->ch[]=v;
else u->ch[]=v;
}
v->fa=u;
u->maintain();
} int n,m,C,K;
int col_cnt[N][],col_vis[N][],q[N],a[N];
map<pair<int,int>,int> mp; Node* build(int l,int r,Node* fa,int* q,int c) {
if(r<l) return null;
int mid=l+r>>;
Node *u=node[q[mid]][c];
u->init(a[q[mid]]);
u->fa=fa;
u->ch[]=build(l,mid-,u,q,c);
u->ch[]=build(mid+,r,u,q,c);
u->maintain();
return u;
}
void bfs(int u,int c) {
static int q[M],f,r;
f=r=;
col_vis[u][c]=;
q[r++]=u;
while(f<r) {
int u=q[f++];
trav(u,i) if(e[i].w==c&&!col_vis[e[i].v][c]){
col_vis[e[i].v][c]=;
q[r++]=e[i].v;
break;
}
}
build(,r-,null,q,c);
} int connect(Node* u,Node* v) {
splay(u); splay(v);
return u->fa!=null;
}
int querymax(Node* u,Node* v) {
splay(u),splay(v,u);
int d=v==u->ch[];
return max(max(u->ori,v->ori),v->ch[d^]->v);
} int main()
{
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
null=new Node();
n=read(),m=read(),C=read(),K=read();
FOR(i,,n) a[i]=read();
FOR(i,,m) {
int u=read(),v=read(),w=read();
w++;
adde(u,v,w),adde(v,u,w);
col_cnt[u][w]++;
col_cnt[v][w]++;
if(u>v) swap(u,v);
mp[make_pair(u,v)]=w;
}
FOR(i,,n) FOR(j,,C) {
node[i][j]=&nodepool[(i-)*C+j-];
node[i][j]->init(); //³õʼ»¯ÄÚ´æ³Ø
}
FOR(i,,C) FOR(j,,n)
if(!col_vis[j][i]&&col_cnt[j][i]==) bfs(j,i);
FOR(i,,K) {
int op=read(),x,y,w;
if(x>y) swap(x,y);
if(op==) {
x=read(),y=read();
a[x]=y;
FOR(i,,C) {
splay(node[x][i]);
node[x][i]->ori=node[x][i]->v=y;
node[x][i]->maintain();
}
} else
if(op==) {
x=read(),y=read();
if(x>y) swap(x,y);
w=read(); w++;
if(!mp.count(make_pair(x,y))) puts("No such edge.");
else {
int old=mp[make_pair(x,y)];
if(old==w) { puts("Success."); continue; }
if(col_cnt[x][w]+> || col_cnt[y][w]+>) puts("Error 1.");
else if(connect(node[x][w],node[y][w])) puts("Error 2.");
else {
split(node[x][old],node[y][old]);
merge(node[x][w],node[y][w]);
--col_cnt[x][old];
--col_cnt[y][old];
++col_cnt[x][w];
++col_cnt[y][w];
mp[make_pair(x,y)]=w;
puts("Success.");
}
}
} else {
w=read(); w++;
x=read(),y=read();
if(x==y) printf("%d\n",a[x]);
else if(!connect(node[x][w],node[y][w])) puts("-1");
else printf("%d\n",querymax(node[x][w],node[y][w]));
}
}
return ;
}

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

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

  1. bzoj 2816: [ZJOI2012]网络 (LCT 建多棵树)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2816 题面: http://www.lydsy.com/JudgeOnline/upload ...

  2. BZOJ.2816.[ZJOI2012]网络(LCT)

    题目链接 BZOJ 洛谷 对每种颜色维护一个LCT,保存点之间的连接关系. 修改权值A[x]和所有Max[x]都要改: 修改边的颜色先枚举所有颜色,看是否在某种颜色中有边,然后断开.(枚举一遍就行啊 ...

  3. 【刷题】BZOJ 2816 [ZJOI2012]网络

    Description http://www.lydsy.com/JudgeOnline/upload/zjoi2012.pdf Solution 维护树上联通块的信息,支持动态加边删边 LCT 总共 ...

  4. 洛谷 2173 BZOJ 2816 [ZJOI2012]网络

    [题解] 明显的LCT模板题,c种颜色就开c棵LCT好了.. #include<cstdio> #include<algorithm> #define N 100010 #de ...

  5. 2816: [ZJOI2012]网络

    传送们 把一个点拆成c个即可 浪费时间的水题... //Achen #include<algorithm> #include<iostream> #include<cst ...

  6. 洛谷 P2173 [ZJOI2012]网络 解题报告

    P2173 [ZJOI2012]网络 题目描述 有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相同颜色的边不超过两条. 图中不存在同色的环, ...

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

    2816 思路: 多个LCT: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 10005 #define l ...

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

    题目: http://www.lydsy.com/JudgeOnline/problem.php?id=2816 思路: 第一个条件看完暂时还没什么想法 看完第二个,发现每一个颜色都是一个森林 进而想 ...

  9. bzoj千题计划223:bzoj2816: [ZJOI2012]网络

    http://www.lydsy.com/JudgeOnline/problem.php?id=2816 每种颜色搞一个LCT 判断u v之间有边直接相连: 如果u和v之间有边相连,那么他们的深度相差 ...

随机推荐

  1. ExtJS4.2学习(六)表格分页与通过后台脚本获得分页数据

    鸣谢:http://www.shuyangyang.com.cn/jishuliangongfang/qianduanjishu/2013-11-12/175.html --------------- ...

  2. Educational Codeforces Round 5 B

    Problem B:http://codeforces.com/contest/616/problem/B B. Dinner with Emma 题意:一对夫妻要去餐厅吃晚饭,Emma 想去最豪华( ...

  3. JAVA面试题:69道Spring面试题和答案

    目录 Spring 概述 依赖注入 Spring beans Spring注解 Spring数据访问 Spring面向切面编程(AOP) Spring MVC Spring 概述 1. 什么是spri ...

  4. [mock]12月11日

    给出一个二叉搜索树的先序遍历,要求重新构造出这个二叉搜索树.一开始给出了一个递归的算法,指出复杂度有更优的解法.然后想出来一个O(n)的算法,就是使用一个栈,然后依次判断新的节点比原来的大还是小,然后 ...

  5. ENVI5.1安装破解教程

    原文地址:  ENVI5.1安装破解_百度经验 http://jingyan.baidu.com/article/020278118b5ded1bcd9ce57a.html   ENVI5.1_x86 ...

  6. Agri Net POJ1258 && Constructing Roads POJ2421

    题意,在给出的图中,使用最小花费的边,使这个图仍然连通. #include <cstdio> #include <algorithm> #include <cstring ...

  7. CentOS7.1 JDK安装 和 CentOS7.1配置yum源

    1.卸载自带OPENJDK #查看自身jdk java -verson #查看自身安装的java  rpm -qa | grep java #显示如下 python-javapackages-3.4. ...

  8. Git教程(7)用合并还是变基?

    合并或变基前的样子:分支experiment与master两个分支都产生了提交. 图1. 未合并或变基前的样子 合并 原理: 找到两个分支的最末提交和最近的共同祖先,在执行git merge时所处的分 ...

  9. 第三部分 MediaPlayer的主要实现分析

    第三部分 MediaPlayer的主要实现分析 3.1 JAVA程序部分    在packages/apps/Music/src/com/android/music/目录的MediaPlaybackS ...

  10. poj3186 poj3267

    两道很不错的dp 3186很神似回文词,合并石子之类的问题: 一开始不知道怎么在dp方程中体现权值天数,很来才想起来 对于一段区间[i,j],里面的东西必然是要卖完的 又因为只能从两头开始卖,所以 d ...