• 【CF576E】Painting Edges 线段树按时间分治+并查集


    【CF576E】Painting Edges

    题意:给你一张n个点,m条边的无向图,每条边是k种颜色中的一种,满足所有颜色相同的边内部形成一个二分图。有q个询问,每次询问给出a,b代表将编号为a的边染成颜色b,但如果染色后不能满足所有颜色相同的边内部都是二分图就不染。问你每次是否能染成功。

    $n,m,qle 5 imes 10^5,kle 50$

    题解:本题看起来要求在线,实质上完全可以离线。

    如果没有不染这种操作的话,那么直接线段树按时间分治+并查集按秩合并就完事了。但如果有呢?我们先假设所有的都能染,那么每个操作都对应着线段树上的一段区间。在线段树处理到一个叶子时,如果发现不能染,那么就把这个操作对应的区间全都修改掉即可。时间复杂度还是一个log的。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #define lson x<<1
    #define rson x<<1|1
    using namespace std;
    const int maxn=500010;
    int n,m,K,Q,top;
    int pa[maxn],pb[maxn],last[maxn],pre[maxn],nxt[maxn],qa[maxn],qb[maxn],f[51][maxn],rnk[51][maxn];
    bool g[51][maxn];
    int sa[maxn],sb[maxn];
    vector<int> v[maxn<<2];
    vector<int>::iterator it;
    inline char nc()
    {
    	static char buf[100000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=nc();
    	while(!isdigit(gc))	{if(gc=='-')	f=-f;	gc=nc();}
    	while(isdigit(gc))	ret=ret*10+(gc^'0'),gc=nc();
    	return ret*f;
    }
    void updata(int l,int r,int x,int a,int b,int c)
    {
    	if(a<=l&&r<=b)
    	{
    		v[x].push_back(c);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(a<=mid)	updata(l,mid,lson,a,b,c);
    	if(b>mid)	updata(mid+1,r,rson,a,b,c);
    }
    void dfs(int l,int r,int x)
    {
    	int now=top;
    	for(it=v[x].begin();it!=v[x].end();it++)
    	{
    		if(!qb[*it])	continue;
    		int x=pa[qa[*it]],y=pb[qa[*it]],z=qb[*it];
    		bool flag=1;
    		while(f[z][x])	flag^=g[z][x],x=f[z][x];
    		while(f[z][y])	flag^=g[z][y],y=f[z][y];
    		if(x==y)	continue;
    		if(rnk[z][x]>rnk[z][y])	swap(x,y);
    		f[z][x]=y,g[z][x]=flag,sa[++top]=x,sb[top]=z;
    		if(rnk[z][x]==rnk[z][y])	rnk[z][y]++,sb[top]=-z;
    	}
    	if(l==r)
    	{
    		int x=pa[qa[l]],y=pb[qa[l]],z=qb[l];
    		bool flag=1;
    		while(f[z][x])	flag^=g[z][x],x=f[z][x];
    		while(f[z][y])	flag^=g[z][y],y=f[z][y];
    		if(x==y&&flag)	qb[l]=qb[pre[l]],puts("NO");
    		else	puts("YES");
    		while(top>now)
    		{
    			if(sb[top]<0)	sb[top]=-sb[top],rnk[sb[top]][f[sb[top]][sa[top]]]--;
    			f[sb[top]][sa[top]]=0,top--;
    		}
    		return ;
    	}
    	int mid=(l+r)>>1;
    	dfs(l,mid,lson),dfs(mid+1,r,rson);
    	while(top>now)
    	{
    		if(sb[top]<0)	sb[top]=-sb[top],rnk[sb[top]][f[sb[top]][sa[top]]]--;
    		f[sb[top]][sa[top]]=0,top--;
    	}
    }
    int main()
    {
    	n=rd(),m=rd(),K=rd(),Q=rd();
    	int i;
    	for(i=1;i<=m;i++)	pa[i]=rd(),pb[i]=rd();
    	for(i=1;i<=Q;i++)
    	{
    		qa[i]=rd(),qb[i]=rd();
    		if(last[qa[i]])	nxt[last[qa[i]]]=i,pre[i]=last[qa[i]];
    		last[qa[i]]=i,nxt[i]=Q+1;
    	}
    	for(i=1;i<=Q;i++)	if(i+1<=nxt[i]-1)	updata(1,Q,1,i+1,nxt[i]-1,i);
    	dfs(1,Q,1);
    	return 0;
    }
  • 相关阅读:
    Ubuntu 16.04
    每天一道LeetCode--389. Find the Difference
    每天一道LeetCode--371. Sum of Two Integers
    Ubuntu 16.04 小飞机启动失败
    每天一道LeetCode--344. Reverse String
    leetcode1458 Max Dot Product of Two Subsequences
    CF1313C2 Skyscrapers (hard version)
    CF1295C Obtain The String
    CF1251D Salary Changing
    CF1286A Garland
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8682737.html
Copyright © 2020-2023  润新知