codeforces #576E Painting Edges 分治+并查集

22 篇文章 0 订阅
9 篇文章 0 订阅

题目大意:给定一张 n 个点m条边的无向图,每条边有一个颜色(初始为无色), q 次操作,每次将一条边染为k种颜色之一,要求染完后对于任意 i=1...k ,当只有颜色为 i 的边存在的时候这张图是一个二分图,如果不满足条件就不进行修改,对于每次修改输出是否成功

这显然是一个动态二分图问题,分治并查集解法戳这里
但是这道题我们并不知道每条边的具体存在时间
因此我们这样:
假设每次修改都生效,我们把每条边的第一种颜色的存在时间加入分治结构(其实就是线段树)
DFS的过程中,如果DFS到一个叶节点时,判断当前修改能否执行,这样我们就得到了这条边在下一个时间段的颜色,然后将这条边的下一个时间段加入分治结构
时间复杂度O(qlogqlogn)

#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 500500
#define col first
#define num second
#define time second
#define operation second
using namespace std;
int n,m,k,q;

struct edge{
    int x,y;
}edges[M];

pair<int,int> queries[M];
//first-color second-edge number

queue<pair<int,int> > modifictions[M];
//first-color second-time

vector<pair<int,int> > v[M<<2];
//first-color second-edge number

struct Union_Find_Set;

pair<Union_Find_Set*,int> stack[M<<2];int top;
//first-color second-operation

int color[M];

struct Union_Find_Set{
    int fa[M];
    char rank[M],dis[M];
    int Find(int x)
    {
        if(!fa[x])
            return x;
        return Find(fa[x]);
    }
    int Distance(int x)
    {
        if(!fa[x])
            return 0;
        return dis[x]^Distance(fa[x]);
    }
    void Union(int x,int y)
    {
        int fx=Find(x),fy=Find(y);
        if(fx==fy) return ;
        if(rank[fx]>rank[fy])
            swap(x,y),swap(fx,fy);
        if(rank[fx]==rank[fy])
            ++rank[fy],stack[++top]=pair<Union_Find_Set*,int>(this,-fy);
        dis[fx]=Distance(x)^Distance(y)^1;
        fa[fx]=fy;
        stack[++top]=pair<Union_Find_Set*,int>(this,fx);
    }
}dsu[51];

void Restore(int bottom)
{
    while(top>bottom)
    {
        if(stack[top].second<0)
            stack[top].first->rank[-stack[top].second]--;
        else
            stack[top].first->fa[stack[top].second]=0;
        top--;
    }
}

void Insert(int p,int x,int y,int l,int r,pair<int,int> val)
{
    int mid=x+y>>1;
    if(x==l&&y==r)
    {
        v[p].push_back(val);
        return ;
    }
    if(r<=mid)
        Insert(p<<1,x,mid,l,r,val);
    else if(l>mid)
        Insert(p<<1|1,mid+1,y,l,r,val);
    else
        Insert(p<<1,x,mid,l,mid,val) , Insert(p<<1|1,mid+1,y,mid+1,r,val);
}

void Divide_And_Conquer(int p,int x,int y)
{
    int i,mid=x+y>>1,bottom=top;
    for(i=0;i<(signed)v[p].size();i++)
    {
        int x=edges[v[p][i].second].x;
        int y=edges[v[p][i].second].y;
        dsu[v[p][i].first].Union(x,y);
    }
    if(x==y)
    {
        Union_Find_Set &dsu=::dsu[queries[mid].col];
        int x=edges[queries[mid].num].x;
        int y=edges[queries[mid].num].y;
        if( dsu.Find(x)!=dsu.Find(y) || dsu.Distance(x)^dsu.Distance(y) )
            puts("YES"),color[queries[mid].num]=queries[mid].col;
        else
            puts("NO");
        modifictions[queries[mid].num].pop();
        if(mid!=q)
            Insert(1,1,q,mid+1,modifictions[queries[mid].num].front().time,pair<int,int>(color[queries[mid].num],queries[mid].num));
    }
    else
        Divide_And_Conquer(p<<1,x,mid),Divide_And_Conquer(p<<1|1,mid+1,y);
    Restore(bottom);
}

int main()
{
    #ifdef PoPoQQQ
    //freopen("576E.in","r",stdin);
    //freopen("576E.out","w",stdout);
    #endif
    int i;
    cin>>n>>m>>k>>q;
    for(i=1;i<=m;i++)
        scanf("%d%d",&edges[i].x,&edges[i].y);
    for(i=1;i<=q;i++)
    {
        scanf("%d%d",&queries[i].num,&queries[i].col);
        modifictions[queries[i].num].push(pair<int,int>(queries[i].col,i));
    }
    for(i=1;i<=m;i++)
        modifictions[i].push(pair<int,int>(0,q));
    Divide_And_Conquer(1,1,q);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值