洛谷 P2173 [ZJOI2012]网络 解题报告
P2173 [ZJOI2012]网络
题目描述
有一个无向图G,每个点有个权值,每条边有一个颜色。这个无向图满足以下两个条件:
对于任意节点连出去的边中,相同颜色的边不超过两条。
图中不存在同色的环,同色的环指相同颜色的边构成的环。
在这个图上,你要支持以下三种操作:
修改一个节点的权值。
修改一条边的颜色。
查询由颜色c的边构成的图中,所有可能在节点u到节点v之间的简单路径上的节点的权值的最大值。
输入输出格式
输入格式:
输入文件network.in的第一行包含四个正整数N, M, C, K,其中N为节点个数,M为边数,C为边的颜色数,K为操作数。
接下来N行,每行一个正整数vi,为节点i的权值。
之后M行,每行三个正整数u, v, w,为一条连接节点u和节点v的边,颜色为w。满足1 ≤ u, v ≤ N,0 ≤ w < C,保证u ≠ v,且任意两个节点之间最多存在一条边(无论颜色)。
最后K行,每行表示一个操作。每行的第一个整数k表示操作类型。
k = 0为修改节点权值操作,之后两个正整数x和y,表示将节点x的权值vx修改为y。
k = 1为修改边的颜色操作,之后三个正整数u, v和w,表示将连接节点u和节点v的边的颜色修改为颜色w。满足0 ≤ w < C。
k = 2为查询操作,之后三个正整数c, u和v,表示查询所有可能在节点u到节点v之间的由颜色c构成的简单路径上的节点的权值的最大值。如果不存在u和v之间不存在由颜色c构成的路径,那么输出“-1”。
输出格式:
输出文件network.out包含若干行,每行输出一个对应的信息。
1.对于修改节点权值操作,不需要输出信息。
2.对于修改边的颜色操作,按以下几类输出:
a) 若不存在连接节点u和节点v的边,输出“No such edge.”。
b) 若修改后不满足条件1,不修改边的颜色,并输出“Error 1.”。
c) 若修改后不满足条件2,不修改边的颜色,并输出“Error 2.”。
d) 其他情况,成功修改边的颜色,并输出“Success.”。
输出满足条件的第一条信息即可,即若同时满足b和c,则只需要输出“Error 1.”。
3.对于查询操作,直接输出一个整数。
数据规模
对于30%的数据:N ≤ 1000,M ≤ 10000,C ≤ 10,K ≤ 1000。
另有20%的数据:N ≤ 10000,M ≤ 100000,C = 1,K ≤ 100000。
对于100%的数据:N ≤ 10000,M ≤ 100000,C ≤ 10,K ≤ 100000。
说实话题目并不难,发现\(C<=10\)以后我们就可以暴力对每种颜色建一个LCT搞一搞了
这里我用map判断是否直接相连
条件1统计度,条件2看联通
注意要特判更改前后的颜色是否相同(否则会被判成2)
我调了N久。。码力太差了
Code:
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
const int N=1e5+10;
int max(int x,int y){return x>y?x:y;}
int mx[N],val[N],ch[N][2],par[N],tag[N],s[N],tot;
#define ls ch[now][0]
#define rs ch[now][1]
#define fa par[now]
bool isroot(int now){return ch[fa][0]==now||ch[fa][1]==now;}
int identity(int now){return ch[fa][1]==now;}
void connect(int f,int now,int typ){fa=f;ch[f][typ]=now;}
void Reverse(int now){int tmp=ls;ls=rs,rs=tmp;tag[now]^=1;}
void updata(int now){mx[now]=max(val[now],max(mx[ls],mx[rs]));}
void Rotate(int now)
{
int p=fa,typ=identity(now);
connect(p,ch[now][typ^1],typ);
if(isroot(p)) connect(par[p],now,identity(p));
else fa=par[p];
connect(now,p,typ^1);
updata(p),updata(now);
}
void pushdown(int now)
{
if(tag[now])
{
if(ls) Reverse(ls);
if(rs) Reverse(rs);
tag[now]^=1;
}
}
void splay(int now)
{
while(isroot(now)) s[++tot]=now,now=fa;
s[++tot]=now;
while(tot) pushdown(s[tot--]);
now=s[1];
for(;isroot(now);Rotate(now))
if(isroot(fa))
Rotate(identity(now)^identity(fa)?now:fa);
}
void access(int now)
{
for(int las=0;now;las=now,now=fa)
splay(now),rs=las,updata(now);
}
void evert(int now){access(now),splay(now),Reverse(now);}
void link(int u,int v)
{
evert(u);par[u]=v;
}
void cat(int u,int v)
{
evert(u),access(v),splay(v);
ch[v][0]=par[u]=0;
updata(v);
}
void change(int now,int va)
{
splay(now),val[now]=va,updata(now);
}
int findroot(int now)
{
access(now),splay(now);
while(ls)
now=ls;
return now;
}
int query(int u,int v)
{
evert(u),access(v),splay(v);
if(findroot(v)!=u) return -1;
return mx[v];
}
int n,m,c,k,du[N];
map <int,int> ma[N/10];
int main()
{
scanf("%d%d%d%d",&n,&m,&c,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",val+i);
mx[i]=val[i];
for(int j=1;j<c;j++)
val[j*n+i]=val[i],mx[j*n+i]=val[i];
}
for(int u,v,w,i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
ma[u][v]=ma[v][u]=w+1;
++du[w*n+u],++du[w*n+v];
link(w*n+u,w*n+v);
}
for(int op,u,v,w,i=1;i<=k;i++)
{
scanf("%d%d%d",&op,&u,&v);
if(op==0)
{
for(int j=0;j<c;j++)
change(u+j*n,v);
}
else if(op==1)
{
scanf("%d",&w);
if(!ma[u][v])
{
printf("No such edge.\n");
continue;
}
if(ma[u][v]==w+1)
{
printf("Success.\n");
continue;
}
int lu=u+(ma[u][v]-1)*n,lv=v+(ma[u][v]-1)*n,vv=v,uu=u;
u+=w*n,v+=w*n;
if(du[u]>1||du[v]>1)
{
printf("Error 1.\n");
continue;
}
if(findroot(u)==findroot(v))
{
printf("Error 2.\n");
continue;
}
ma[uu][vv]=ma[vv][uu]=w+1;
--du[lu],--du[lv],++du[u],++du[v];
printf("Success.\n");
cat(lu,lv);
link(u,v);
}
else
{
scanf("%d",&w);
printf("%d\n",query(u*n+v,u*n+w));
}
}
return 0;
}
2018.9.1