zoukankan      html  css  js  c++  java
  • 【CF1555F】Good Graph

    题目

    题目链接:https://codeforces.com/contest/1555/problem/F
    (n) 个点,有 (Q) 次操作。每次操作给出 (x,y,z),如果满足在 (x,y) 之间加了一条权值为 (z) 的边后,不存在任意一个简单环的所有边权值异或和为 (0),那么就连上这条边,否则忽略这条边。
    对于每一条边输出它是否被连上了。
    (nleq 3 imes 10^5,Qleq 5 imes 10^5,zin{0,1})

    思路

    考场被卡常了。。我把

    stack<int> st;
    st.push(x);
    for (int y=x;notrt(y);y=fa[y]) st.push(fa[y]);
    for (;st.size();st.pop()) pushdown(st.top());
    

    改成了

    void down(int x)
    {
    	if (notrt(x)) down(fa[x]);
    	pushdown(x);
    }
    

    就从 3s 跑到了 0.7s??


    有一个显而易见的结论:如果加边后存在一条边同时在两个简单环内,那么必然不会加这条边。因为如果两个简单环的异或和都为 (1),那么这两个环拼在一起去掉重复边形成的大环的异或和一定为 (0)
    所以说我们需要支持加边,路径覆盖,询问路径异或和。采用 LCT 即可。
    为了卡常,我赛后参考了 WZYYN 大爷的代码,没有在 LCT 上维护异或和,而是用带权并查集维护异或和。事实上慢的地方并不是那里 /fad。
    而且由于每次路径覆盖一定是覆盖之前没有被覆盖的部分,所以不用懒标记,直接暴力覆盖即可。
    时间复杂度 (O(Qlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=800010;
    int n,m,cnt,father[N],xors[N];
    
    int find(int x)
    {
    	if (x==father[x]) return x;
    	int y=father[x]; father[x]=find(y);
    	xors[x]^=xors[y];
    	return father[x];
    }
    
    int read()
    {
    	int d=0; char ch=getchar();
    	while (!isdigit(ch)) ch=getchar();
    	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d;
    }
    
    struct LCT
    {
    	int ch[N][2],fa[N];
    	bool rev[N],vis[N],flag[N];
    	
    	bool pos(int x) { return ch[fa[x]][1]==x; }
    	bool notrt(int x) {	return (ch[fa[x]][0]==x) || (ch[fa[x]][1]==x); }
    	
    	void pushup(int x)
    	{
    		flag[x]=flag[ch[x][0]]|flag[ch[x][1]]|vis[x];
    	}
    	
    	void pushdown(int x)
    	{
    		if (rev[x])
    		{
    			int lc=ch[x][0],rc=ch[x][1];
    			if (lc) swap(ch[lc][0],ch[lc][1]),rev[lc]^=1;
    			if (rc) swap(ch[rc][0],ch[rc][1]),rev[rc]^=1;
    			rev[x]=0;
    		}
    	}
    	
    	void rotate(int x)
    	{
    		int y=fa[x],z=fa[y],k=pos(x),c=ch[x][k^1];
    		if (notrt(y)) ch[z][pos(y)]=x; ch[x][k^1]=y; ch[y][k]=c;
    		if (c) fa[c]=y; fa[y]=x; fa[x]=z;
    		pushup(y); pushup(x);
    	}
    	
    	void down(int x)
    	{
    		if (notrt(x)) down(fa[x]);
    		pushdown(x);
    	}
    	
    	void splay(int x)
    	{
    		down(x);
    		for (;notrt(x);rotate(x))
    			if (notrt(fa[x])) rotate(pos(x)==pos(fa[x])?fa[x]:x);
    	}
    	
    	void access(int x)
    	{
    		for (int y=0;x;y=x,x=fa[x])
    		{
    			splay(x); ch[x][1]=y;
    			pushup(x);
    		}
    	}
    	
    	void makert(int x)
    	{
    		access(x); splay(x);
    		rev[x]^=1; swap(ch[x][0],ch[x][1]);
    	}
    	
    	void link(int x,int y)
    	{
    		makert(x); fa[x]=y;
    	}
    	
    	void update(int x)
    	{
    		if (x>n) vis[x]=1;
    		if (ch[x][0]) update(ch[x][0]);
    		if (ch[x][1]) update(ch[x][1]);
    		pushup(x);
    	}
    }lct;
    
    int main()
    {
    	n=cnt=read(); m=read();
    	for (int i=1;i<=n;i++) father[i]=i;
    	for (int i=1;i<=m;i++)
    	{
    		int x=read(),y=read(),z=read();
    		if (find(x)!=find(y))
    		{
    			int xx=find(x),yy=find(y);
    			father[xx]=yy; xors[xx]=xors[x]^xors[y]^z; 
    			cnt++; lct.link(x,cnt); lct.link(y,cnt);
    			cout<<"YES
    ";
    		}
    		else
    		{
    			if (xors[x]^xors[y]==z) { cout<<"NO
    "; continue; }
    			lct.makert(x); lct.access(y); lct.splay(x);
    			if (lct.flag[x]) { cout<<"NO
    "; continue; }
    			lct.update(x);
    			cout<<"YES
    ";
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    elasticsearch入门 (三 ik 分词器安装)
    elasticsearch入门(二 基础api实例)
    elasticsearch入门(一 基础搭建)
    mysql 错误代码 1045 解决
    信号强度概念
    c语言中,在结构体中如何将void *转存为具体需要的数据类型
    我的论文
    I2C 上拉电阻选择计算公式
    SD卡两种操作模式在项目中应用的比较
    2017 年 年会过后的感想
  • 原文地址:https://www.cnblogs.com/stoorz/p/15083270.html
Copyright © 2011-2022 走看看