P2173 [ZJOI2012] 网络
P2173 [ZJOI2012] 网络
题目描述
有一个无向图 \(G\),每个点有个权值,每条边有一个颜色。这个无向图满足以下两个条件:
1、 对于任意节点连出去的边中,相同颜色的边不超过两条。
2、图中不存在同色的环,同色的环指相同颜色的边构成的环。
在这个图上,你要支持以下三种操作:
-
0 x y表示把节点 \(x\) 的权值改为 \(y\) -
1 u v w表示将边 \((u,v)\) 的颜色改为 \(w\)。 -
2 c u v表示查询由颜色 \(c\) 的边构成的图中,所有可能在 \(u \to v\) 之间的简单路径上的节点的权值的最大值。
输入格式
第一行四个正整数 \(n,m,C,k\),分别表示节点数、边数、颜色数和操作数。
接下来 \(n\) 行,每行一个正整数 \(v_i\),为节点 \(i\) 的权值。
之后 \(m\) 行,每行三个正整数 \(u,v,w\),为一条连接 \(u,v\) 节点的边,颜色为\(w\)。
最后 \(k\) 行,每行若干个正整数,表示一次操作。
输出格式
输出若干行,每行输出一个对应的信息。
1、 对于修改节点权值操作,不需要输出信息。
2、对于修改边的颜色操作,按以下几类输出:
-
若不存在连接节点 \(u\) 和节点 \(v\) 的边,输出
No such edge.。 -
若修改后不满足条件 \(1\),不修改边的颜色,并输出
Error 1.。 -
若修改后不满足条件 \(2\),不修改边的颜色,并输出
Error 2.。 -
其他情况,成功修改边的颜色,并输出
Success.。
输出满足条件的第一条信息即可,即若同时不满足条件 \(1,2\) ,则只需要输出Error 1.。
3、 对于查询操作,输出一个整数表示答案。若 \(u,v\) 之间没有颜色 \(c\) 构成的路径,则输出 \(-1\)。
【数据范围】
对于 \(100\%\) 的数据:\(n ≤ 10^4\),\(m ≤ 10^5\),\(C ≤ 10\),\(k ≤ 10^5\)。
\(1\le u,v,x \le n\),\(0 \le c < C\),保证图中没有重边和自环。
说句闲话
终于写到 LCT 了,我自己都没想到我居然欠了这么多解题报告没写,感觉今天补不完啊 QAQ.
Solution:
首先我们狠狠阅读一下题目:
1、 对于任意节点连出去的边中,相同颜色的边不超过两条。
2、图中不存在同色的环,同色的环指相同颜色的边构成的环。
\(C ≤ 10\)
这启示我们针对每个颜色建一颗 LCT.然后就很板子了:
操作1我们就直接改颜色,操作二在经过一系列判断之后把原颜色的 LCT 上的边删掉,然后在新的颜色的 LCT 上加边,操作3直接 splite 就行。
操作2的“一系列操作”详见代码。
Code:
#include<bits/stdc++.h>
const int N=1e5+5;
const int C=10;
using namespace std;
int st[N];
int Max(int x,int y){return x>y ? x : y;}
int w[N];
struct LCT{
struct Tree{
int mx,val,tag,ff,ch[2];
}t[N<<2];
#define ls t[x].ch[0]
#define rs t[x].ch[1]
#define fa t[x].ff
inline bool isroot(int x)
{
return (t[fa].ch[0]==x||t[fa].ch[1]==x);
}
inline void pushup(int x)
{
t[x].mx=Max(Max(t[ls].mx,t[rs].mx),t[x].val);
return;
}
inline void rev(int x)
{
swap(t[x].ch[0],t[x].ch[1]);
t[x].tag^=1;
return ;
}
inline void pushdown(int x)
{
if(t[x].tag)
{
if(ls)rev(ls);
if(rs)rev(rs);
t[x].tag=0;
}
return ;
}
inline void rotate(int x)
{
int y=fa,z=t[fa].ff,k=t[fa].ch[1]==x ? 1 : 0;
if(isroot(y))t[z].ch[t[z].ch[1]==y]=x;
t[x].ff=z;
t[y].ch[k]=t[x].ch[!k];
if(t[x].ch[!k])t[t[x].ch[!k]].ff=y;
t[x].ch[!k]=y;
t[y].ff=x;
pushup(y);
}
inline void splay(int x)
{
int y=x,z=0;
st[++st[0]]=y;
while(isroot(y))st[++st[0]]=y=t[y].ff;
while(st[0])pushdown(st[st[0]--]);
while(isroot(x)&&x)//isn't root
{
y=fa,z=t[fa].ff;
if(isroot(y)){rotate((t[y].ch[1]==x)==(t[z].ch[1]==y) ? y : x);}
rotate(x);
}
pushup(x);
}
void access(int x)
{
int y=0;
while(x)
{
splay(x);rs=y;pushup(x);
y=x;x=fa;
}
}
void make_root(int x)//换根
{
access(x);splay(x);
rev(x);
}
int find(int x)
{
access(x);splay(x);
while(ls)pushdown(x),x=ls;
splay(x);
return x;
}
bool splite(int x,int y)
{
make_root(x);
if(find(y)!=x)return 0;
access(y);splay(y);
return 1;
}
bool link(int x,int y)// 意义很明确的函数名称
{
make_root(x);
if(find(y)!=x){t[x].ff=y;return 1;}
return 0;
}
bool cut(int x,int y)// 意义很明确的函数名称
{
make_root(x);
if(find(y)==x&&t[y].ff==x&&t[y].ch[0]==0)
{
t[y].ff=t[x].ch[1]=0;
pushup(x);
return 1;
} return 0;
}
}T[C];
int d[C][N];
int n,m,p,q;
map<pair<int,int>,int> Map;
#define mp(x,y) make_pair(x,y)
void work()
{
cin>>n>>m>>p>>q;
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
for(int j=0;j<p;j++)for(int i=1;i<=n;i++)T[j].t[i].val=T[j].t[i].mx=w[i];
for(int i=1,x,y,col;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&col);
T[col].link(x,y);d[col][x]++;d[col][y]++;
Map[mp(x,y)]=col+1;
Map[mp(y,x)]=col+1;
}
int opt,x,y,z;
for(int i=1;i<=q;i++)
{
scanf("%d%d%d",&opt,&x,&y);
if(opt==0)
{
w[x]=y;
for(int j=0;j<p;j++)
{
T[j].t[x].val=w[x];
T[j].splay(x);
}
continue;
}
scanf("%d",&z);
if(opt==1)
{
if(z==Map[mp(x,y)]-1){printf("Success.\n");continue;}
if(!Map[mp(x,y)]){printf("No such edge.\n");continue;}
if(d[z][x]==2||d[z][y]==2){printf("Error 1.\n");continue;}
if(T[z].link(x,y))
{
int col=Map[mp(x,y)]-1;Map[mp(x,y)]=Map[mp(y,x)]=z+1;
T[col].cut(x,y);
d[col][x]--,d[col][y]--;
d[z][x]++,d[z][y]++;
printf("Success.\n");
}
else {printf("Error 2.\n");}
}
if(opt==2)
{
if(T[x].splite(y,z))
{
printf("%d\n",Max(T[x].t[z].mx,T[x].t[z].val));
}
else
{
printf("%d\n",-1);
}
}
}
}
int main()
{
//freopen("network.in","r",stdin);
//freopen("network.out","w",stdout);
work();
return 0;
}

浙公网安备 33010602011771号