洛谷 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
洛谷 P2173 [ZJOI2012]網絡 解題報告