小A得了忧郁综合症,小B正在想办法开导她。
机智的小B决定陪着小A玩游戏,他从魔法的世界里变出一张无向联通图,每条边上都有边权。小B定义一条路径的权值为所有经过边中的最大权值,小A则定义两点的最短路径为所有路径中权值最小的路径权。
每次小A和小B会选出k对点mi_1,mi_2,分别计算出mi_1,mi_2的最短路径ti,然后小B会拿出k堆灵魂宝石,每堆有ti个。然后小A先从一堆中选出若干个灵魂宝石拿走,接下来小B重复同样的操作,如此反复,直到取走最后一颗灵魂宝石,然后取走最后一颗宝石的人获胜。
小B认为这样游戏太简单,于是他会不定期向这张图上加上一些边,以增大游戏难度。
小A具有预知未来的能力,她看到了自己和小B在未来游戏中的选择,以及小B增加的边。现在对于每次游戏,小A想知道自己是否存在必胜的方法。但是预知未来已经消耗了她太多精力,出于疲惫她只好找到了你。
第一行三个数N和M和K,表示这张无向图初始的点数与边数,以及每次询问的点对的个数;
接下来M行,每行三个数u,v,q,表示点u和点v之间存在一条权值为q的
边;
接下来一行一个数Q,表示操作总数;
接下来Q行,表示操作,每行格式为下面两条中的一条:
1.add u v q:表示在u与v之间加上一条边权为q的边;
2.game m1_1 m1_2 … mk_1 mk_2:表示一次游戏中选择的k对点。
数据保证1≤u,v,mi_1,mi_2≤n,1≤q,mi_1≠mi_2
对于每个game输出一行,若小A存在必胜策略,则输出“madoka”,否则输出“Baozika”,以回车结尾
5 6 2
1 2 3
2 3 6
4 2 4
5 3 5
3 4 5
5 1 5
4
game 1 3 4 3
game 1 5 2 4
add 2 5 4
game 1 5 3 4
Baozika
madoka
madoka
首先考虑获胜策略。 k 堆石子,每堆石子数量为 ai 。
A 和 B 玩游戏,轮流从其中某一堆石子中取出若干个石子,最后取完石子的人获胜。
结论:如 a1 xor a2 xor ... xor ak=0 ,则先手输,否则先手赢, xor 表示异或。
证明:若 a1 xor a2 xor ... xor an≠0 ,则一定可以从其中某堆石子中取出一些石子,
使得剩下的石子数异或结果为 0,若 a1 xor a2 xor ... xor an=0 ,
则进行一次取石子操作后 a1 xor a2 xor ... xor an 一定不等于 0,
按照这样的操作下去,最后一定会出现 a1=a2= ... =an=0 的情况。
问题就变成了加边和求路径长。
看到询问次数很少,考虑 倍增+LCA 。
根据最小生成树的性质,我们发现路径一定在 无向图的最小生成树 上。
每次维护最小生成树,完成询问用树上 LCA 即可。
事实上,加入一条边只有可能改变最小生成树上的一条边。
假设加边为 x,y,z ,我们可以找到 x 到 y 的路径上的最大边权。
若该边权 >z ,显然将新边加入更优,否则忽略新边。
再将所有边用 O(N) 的插入排序排序即可。
套上在线 LCA 算法就可以愉快的 AC 了。
时间复杂度 O(D∗NlogN+(Q−D)∗logN) ,其中 D 为加边次数。
注意存边权要开 long long 。
如果加边次数不限呢?直接上 LCT 啊!
用 Link−Cut−Tree 维护最小生成树即可。
若当前加入的边小于当前树中边权的最大值,则将那个最大的边删去,再连当前边。
维护边权的话可以开一个虚点存边权,再连向两个点即可。
注意开够数组范围。
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=5002,M=105001;
struct data
{
int x,y;
LL z;
}a[M];
int tot,num;
int first[N],next[N<<1],en[N<<1];
LL w[N<<1];
int f[N],size[N],fa[N][13],dep[N];
LL g[N][13];
template<typename T>inline T read()
{
T X=0,w=0; char ch=0;
while(ch<'0' || ch>'9') {w|=ch=='-';ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
inline LL max(LL x,LL y)
{
return x>y?x:y;
}
inline bool cmp(data x,data y)
{
return x.zinline int get(int x)
{
return f[x]==x?x:f[x]=get(f[x]);
}
inline bool merge(int x,int y)
{
if(get(x)==get(y)) return false;
if(size[f[x]]return true;
}
inline void insert(int x,int y,LL z)
{
next[++tot]=first[x];
first[x]=tot;
en[tot]=y;
w[tot]=z;
}
inline void dfs(int x)
{
dep[x]=dep[fa[x][0]]+1;
for(int i=first[x];i;i=next[i])
if(en[i]^fa[x][0])
{
fa[en[i]][0]=x;
g[en[i]][0]=w[i];
dfs(en[i]);
}
}
inline LL lca(int x,int y)
{
if(dep[x]0;
for(int i=log2(dep[x]);i>=0;i--)
if(dep[fa[x][i]]>=dep[y])
{
mx=max(mx,g[x][i]);
x=fa[x][i];
}
if(x==y) return mx;
for(int i=log2(dep[x]);i>=0;i--)
if(fa[x][i]!=fa[y][i])
{
mx=max(mx,max(g[x][i],g[y][i]));
x=fa[x][i],y=fa[y][i];
}
mx=max(mx,max(g[x][0],g[y][0]));
return mx;
}
int main()
{
int n=read<int>(),m=read<int>(),k=read<int>();
for(int i=1;i<=m;i++)
a[i].x=read<int>(),a[i].y=read<int>(),a[i].z=read();
sort(a+1,a+1+m,cmp);
for(int i=1;i<=n;i++) size[f[i]=i]=1;
for(int i=1,k=1;i<=m;i++)
if(merge(a[i].x,a[i].y))
{
insert(a[i].x,a[i].y,a[i].z);
insert(a[i].y,a[i].x,a[i].z);
a[++num]=a[i];
if(++k==n) break;
}
dfs(1);
for(int j=1,p=log2(n);j<=p;j++)
for(int i=1;i<=n;i++)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
g[i][j]=max(g[fa[i][j-1]][j-1],g[i][j-1]);
}
int q=read<int>();
while(q--)
{
char ch=getchar();
while(ch!='g' && ch!='a') ch=getchar();
if(ch=='g')
{
LL ans=0;
for(int i=1;i<=k;i++) ans^=lca(read<int>(),read<int>());
if(ans) puts("madoka"); else puts("Baozika");
}else
{
int x=read<int>(),y=read<int>();
LL z=read();
if(lca(x,y)<=z) continue;
tot=fa[1][0]=0;
memset(first,0,sizeof(first));
memset(g,0,sizeof(g));
//a[++num]=(data){x,y,z};
//sort(a+1,a+1+num,cmp);
bool pd=true;
for(int i=1;i<=num;i++)
if(z<=a[i].z)
{
for(int j=++num;j>i;j--) a[j]=a[j-1];
a[i]=(data){x,y,z};
pd=false;
break;
}
if(pd) a[++num]=(data){x,y,z};
for(int i=1;i<=n;i++) size[f[i]=i]=1;
num=0;
for(int i=1,k=1;i<=n;i++)
if(merge(a[i].x,a[i].y))
{
insert(a[i].x,a[i].y,a[i].z);
insert(a[i].y,a[i].x,a[i].z);
a[++num]=a[i];
if(++k==n) break;
}
dfs(1);
for(int j=1,p=log2(n);j<=p;j++)
for(int i=1;i<=n;i++)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
g[i][j]=max(g[fa[i][j-1]][j-1],g[i][j-1]);
}
}
}
return 0;
}
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=110005;
struct data
{
int x,y;
}a[N];
int tot,top;
int fa[N],s[N][2],mx[N],st[N];
LL key[N];
bool rev[N];
template<typename T>inline T read()
{
T X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
inline bool pd(int x)
{
return x==s[fa[x]][1];
}
inline bool isroot(int x)
{
return s[fa[x]][0]^x && s[fa[x]][1]^x;
}
inline void modify(int x)
{
if(x) swap(s[x][0],s[x][1]),rev[x]^=1;
}
inline void update(int x)
{
mx[x]=key[mx[s[x][0]]]>key[mx[s[x][1]]]?mx[s[x][0]]:mx[s[x][1]];
if(key[x]>key[mx[x]]) mx[x]=x;
}
inline void down(int x)
{
if(rev[x])
{
modify(s[x][0]),modify(s[x][1]);
rev[x]=false;
}
}
inline void rotate(int x)
{
int y=fa[x],w=pd(x);
if(s[y][w]=s[x][w^1]) fa[s[x][w^1]]=y;
if((fa[x]=fa[y]) && !isroot(y)) s[fa[y]][pd(y)]=x;
s[fa[y]=x][w^1]=y;
update(y);
}
inline void splay(int x)
{
for(int y=st[top=1]=x;!isroot(y);y=fa[y]) st[++top]=fa[y];
while(top) down(st[top--]);
for(int y;!isroot(x);rotate(x))
if(!isroot(y=fa[x])) rotate(pd(x)==pd(y)?y:x);
update(x);
}
inline void access(int x)
{
for(int y=0;x;x=fa[y=x]) splay(x),s[x][1]=y,update(x);
}
inline void mkroot(int x)
{
access(x),splay(x),modify(x);
}
inline void link(int x,int y)
{
mkroot(x),fa[x]=y;
}
inline void cut(int x,int y)
{
mkroot(x),access(y),splay(y);
fa[x]=s[y][0]=0;
}
inline int get(int x)
{
access(x),splay(x);
int y=x;while(s[y][0]) y=s[y][0];
return y;
}
int main()
{
int n=tot=read<int>(),m=read<int>(),k=read<int>();
for(int i=1;i<=m;i++)
{
int x=read<int>(),y=read<int>();
LL z=read();
a[i]=(data){x,y};
key[mx[++tot]=tot]=z;
if(get(x)^get(y)) link(tot,x),link(tot,y); else
{
mkroot(x),access(y),splay(y);
int del=mx[y];
if(zint q=read<int>();
while(q--)
{
char ch=getchar();
while(ch^'g' && ch^'d') ch=getchar();
if(ch=='g')
{
LL ans=0;
for(int i=1;i<=k;i++)
{
int x=read<int>(),y=read<int>();
mkroot(x),access(y),splay(y);
ans^=key[mx[y]];
}
puts(ans?"madoka":"Baozika");
}else
{
int x=read<int>(),y=read<int>();
LL z=read();
a[++m]=(data){x,y};
key[mx[++tot]=tot]=z;
if(get(x)^get(y)) link(tot,x),link(tot,y); else
{
mkroot(x),access(y),splay(y);
int del=mx[y];
if(zreturn 0;
}