• CodeForces 576E Paingting Edges


    CodeForces 576E Paingting Edges

    https://codeforces.com/contest/576/problem/E

    UJLhRK.png

    Tutorial

    https://blog.csdn.net/PoPoQQQ/article/details/48467731

    首先,这一类在无向图中操作边的题一般采用[线段树分治+可撤销并查集]解决.

    如果我们知道每个修改的作用时间范围,那么就可以很简单的解决这道题,但是问题是每条边的状态是依赖于询问的答案的.

    可以用cdq分治的思想,将每条边按修改分为若干个时间段,我们对于一个叶子询问合并后是否有奇环,然后根据询问的结果,就知道下一个时间段这条边的颜色.这样在对于每个叶子查询的时候,当前并查集的状态都是正确的.

    复杂度(O(q log q log n))

    Code

    #include <cstdio>
    #include <iostream>
    #include <queue>
    #include <vector>
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    #define lson u<<1,l,mid
    #define rson u<<1|1,mid+1,r
    using namespace std;
    inline char gc() {
    //	return getchar();
    	static char buf[100000],*l=buf,*r=buf;
    	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
    }
    template<class T> void rd(T &x) {
    	x=0; int f=1,ch=gc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
    	x*=f;
    }
    const int maxn=5e5+5,maxm=5e5+5,maxq=5e5+5,maxk=50+1;
    const int maxnode=maxq<<2;
    int n,m,k,q,a[maxm],b[maxm],e[maxq],c[maxq],an[maxq];
    int col[maxm];
    queue<int> Q[maxm];
    vector<int> C[maxnode];
    namespace us {
    	int fa[maxk][maxn],siz[maxk][maxn]; bool d[maxk][maxn];
    	struct node {
    		int k,a,b;
    		node(int k=0,int a=0,int b=0):k(k),a(a),b(b){}
    	};
    	vector<node> rec;
    	void init() {
    		for(int i=1;i<=k;++i) for(int j=1;j<=n;++j) fa[i][j]=j,siz[i][j]=1;
    	}
    	int dist(int k,int a) {
    		int re=0;
    		while(fa[k][a]!=a) re^=d[k][a],a=fa[k][a];
    		return re;
    	}
    	int find(int k,int a) {
    		while(fa[k][a]!=a) a=fa[k][a];
    		return a;
    	}
    	inline bool merge(int k,int a,int b) {
    		int da=dist(k,a),db=dist(k,b);
    		a=find(k,a),b=find(k,b);
    		if(a==b) return 0;
    		if(siz[k][a]<siz[k][b]) swap(a,b);
    		fa[k][b]=a,siz[k][a]+=siz[k][b],d[k][b]=da^db^1;
    		rec.push_back(node(k,a,b));
    		return 1;
    	}
    	void restore(int bottom) {
    		while(rec.size()>bottom) {
    			int k=rec.back().k,a=rec.back().a,b=rec.back().b; rec.pop_back();
    			fa[k][b]=b,siz[k][a]-=siz[k][b],d[k][b]=0;
    		}
    	}
    }
    void update(int u,int l,int r,int ql,int qr,int qv) {
    //	debug("%d %d %d %d
    ",l,r,ql,qr);
    	if(l==ql&&r==qr) {
    		C[u].push_back(qv);
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(qr<=mid) update(lson,ql,qr,qv);
    	else if(ql>mid) update(rson,ql,qr,qv);
    	else {
    		update(lson,ql,mid,qv);
    		update(rson,mid+1,qr,qv);
    	}
    }
    void sol(int u,int l,int r) {
    //	debug("%d %d %d
    ",u,l,r);
    	int t=us::rec.size();
    	for(int i=0;i<C[u].size();++i) {
    		int x=C[u][i];
    		us::merge(col[x],a[x],b[x]);
    	}
    	if(l==r) {
    		int u=a[e[l]],v=b[e[l]];
    		if(us::find(c[l],u)!=us::find(c[l],v)||us::dist(c[l],u)^us::dist(c[l],v)) {
    			an[l]=1,col[e[l]]=c[l];
    		}
    		Q[e[l]].pop();
    		if(l!=q) update(1,1,q,l+1,Q[e[l]].front(),e[l]);
    		us::restore(t);
    		return;
    	}
    	int mid=(l+r)>>1;
    	sol(lson);
    	sol(rson);
    	us::restore(t);
    }
    int main() {
    	rd(n),rd(m),rd(k),rd(q);
    	for(int i=1;i<=m;++i) rd(a[i]),rd(b[i]);
    	for(int i=1;i<=q;++i) {
    		rd(e[i]),rd(c[i]);
    		Q[e[i]].push(i);
    	}
    	for(int i=1;i<=m;++i) Q[i].push(q);
    	us::init();
    	sol(1,1,q);
    	for(int i=1;i<=q;++i) puts(an[i]?"YES":"NO");
    	return 0;
    }
    
  • 相关阅读:
    一个面试问题的答案总结
    全局变量与局部变量的特点
    浮点数类型在内存当中是如何存储的
    常用的几种调用约定
    裸函数
    安卓活动的启动模式
    安卓的生命周期
    android中的内部存储与外部存储
    堆栈图学习汇编结束篇最后一个堆栈图的练习
    Android内部存储与外部存储的文件操作类
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/13294003.html
Copyright © 2020-2023  润新知