JZOJ 5466. 【NOIP2017提高A组冲刺11.9】玩游戏

12 篇文章 0 订阅
11 篇文章 0 订阅

Description

小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想知道自己是否存在必胜的方法。但是预知未来已经消耗了她太多精力,出于疲惫她只好找到了你。

Input

第一行三个数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

Output

对于每个game输出一行,若小A存在必胜策略,则输出“madoka”,否则输出“Baozika”,以回车结尾

Sample Input

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

Sample Output

Baozika
madoka
madoka

Data Constraint

Data Constraint

Solution

  • 首先考虑获胜策略。 k 堆石子,每堆石子数量为 ai

  • A 和 B 玩游戏,轮流从其中某一堆石子中取出若干个石子,最后取完石子的人获胜。

  • 结论:如 a1 xor a2 xor ... xor ak=0 ,则先手输,否则先手赢, xor 表示异或。

  • 证明:若 a1 xor a2 xor ... xor an0 ,则一定可以从其中某堆石子中取出一些石子,

  • 使得剩下的石子数异或结果为 0,若 a1 xor a2 xor ... xor an=0

  • 则进行一次取石子操作后 a1 xor a2 xor ... xor an 一定不等于 0,

  • 按照这样的操作下去,最后一定会出现 a1=a2= ... =an=0 的情况。

  • 问题就变成了加边和求路径长

算法1

  • 看到询问次数很少,考虑 倍增+LCA

  • 根据最小生成树的性质,我们发现路径一定在 无向图的最小生成树 上。

  • 每次维护最小生成树,完成询问用树上 LCA 即可。

  • 事实上,加入一条边只有可能改变最小生成树上的一条边。

  • 假设加边为 x,y,z ,我们可以找到 x y 的路径上的最大边权。

  • 若该边权 >z ,显然将新边加入更优,否则忽略新边。

  • 再将所有边用 O(N) 的插入排序排序即可。

  • 套上在线 LCA 算法就可以愉快的 AC 了。

  • 时间复杂度 O(DNlogN+(QD)logN) ,其中 D 为加边次数。

  • 注意存边权要开 long long

算法2

  • 如果加边次数不限呢?直接上 LCT 啊!

  • LinkCutTree 维护最小生成树即可。

  • 若当前加入的边小于当前树中边权的最大值,则将那个最大的边删去,再连当前边。

  • 维护边权的话可以开一个虚点存边权,再连向两个点即可。

  • 注意开够数组范围。

Code(倍增LCA)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
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.z<y.z;
}
inline 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]]<size[f[y]]) swap(x,y);
    size[f[x]]+=size[f[y]];
    f[f[y]]=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]<dep[y]) swap(x,y);
    LL mx=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<LL>();
    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<LL>();
            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<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
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<LL>();
        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(z<key[del])
            {
                cut(del,a[del-n].x),cut(del,a[del-n].y);
                link(tot,x),link(tot,y);
            }
        }
    }
    int 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<LL>();
            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(z<key[del])
                {
                    cut(del,a[del-n].x),cut(del,a[del-n].y);
                    link(tot,x),link(tot,y);
                }
            }
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值