【题目链接】

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. RE:转:一些不常用的html代码

    1. oncontextmenu="window.event.returnvalue=false" 将彻底屏蔽鼠标右键<table border oncontextmenu= ...

  2. springMVC从上传的Excel文件中读取数据

    示例:导入客户文件(Excle文件) 一.编辑customer.xlsx 二.在spring的xml文件设置上传文件大小 <!-- 上传文件拦截,设置最大上传文件大小 10M=10*1024*1 ...

  3. 手机开发类型jquery的框架Zepto(API)

    Zepto是一个轻量级的针对现代高级浏览器的JavaScript库, 它与jquery有着类似的api. 如果你会用jquery,那么你也会用zepto. http://www.html-5.cn/M ...

  4. Flume学习——BasicTransactionSemantics

    org.apache.flume.channel.BasicTransactionSemantics An implementation of basic Transaction semantics ...

  5. python datetime笔记

    python datetime笔记 http://mint-green.diandian.com/post/2011-09-09/4892024 获取当前时间,并通过字符串输出. 格式为:%Y-%m- ...

  6. undefined与null的区别---js

    不错... http://www.ruanyifeng.com/blog/2014/03/undefined-vs-null.html

  7. red5研究(一):下载,工程建立、oflaDemo安装、demo测试

    一.red5下载.添加工程到myeclipse 1,从官网上下载red51.01版本(我下载的是red51.0的版本),下载链接http://www.red5.org/downloads/red5/1 ...

  8. linux netcat命令

    netcat是网络工具中的“瑞士军刀”,它能通过TCP和UDP在网络中读写数据.通过与其他工具结合和重定向,你可以在脚本中以多种方式使用它.使用netcat命令所能完成的事情令人惊讶. netcat所 ...

  9. WIN7 XP设置MTU,提升下载速度

    可能很少有雷友注意过“本机.网络”的“MTU”值对自己网络性能产生的影响.对于追求更快的下载速度来说,MTU值设置不当,就仿佛穿着高跟鞋跑步一般. MTU是什么? “MTU=最大传输单元 单位:字节” ...

  10. 【HDOJ】1699 The comment in cpp

    注意测试数据12/*hduacm// abcd结果是1/*hduacm// ABCD /* 1699 */ #include <iostream> #include <sstream ...