zoukankan      html  css  js  c++  java
  • 【YbtOJ#731】图上询问

    题目

    题目链接:https://www.ybtoj.com.cn/problem/731

    (n,m,Qleq 2 imes 10^5)

    思路

    考场上写了一发 (O(Qsqrt{m}alpha(n))) 回滚莫队没卡过去。。。
    考虑把询问按照右端点离线,我们对于询问 ([l,r]),把 ([1,r]) 的边依次加入 LCT 中并维护最大生成森林,那么我们只需要知道最大生成森林中编号 (geq l) 的边的数量即可。
    那么直接把每一条边看作一个点,可以用并查集维护点是否连通,如果不连通就直接在这两个点直接插入这条边所对应的点并 link 上,否则由于我们把边从小到大插入,只需要查询两点之间的路径点(指 LCT 上的点,也就是原图的点和边。我们可以把原图点的权值设为无限大)权值的最小值,删去这个点(原图的边)再插入新的即可。
    可以用树状数组维护超过 (l) 的边的数量。
    时间复杂度 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=400010;
    int n,m,Q,ans[N],U[N],V[N],father[N];
    
    struct Query
    {
    	int l,r,id;
    }ask[N];
    
    bool cmp(Query x,Query y)
    {
    	return x.r<y.r;
    }
    
    int find(int x)
    {
    	return x==father[x]?x:father[x]=find(father[x]);
    }
    
    struct BIT
    {
    	int c[N];
    	
    	void add(int x,int v)
    	{
    		for (int i=x;i<=m;i+=i&-i)
    			c[i]+=v;
    	}
    	
    	int query(int x)
    	{
    		int ans=0;
    		for (int i=x;i;i-=i&-i)
    			ans+=c[i];
    		return ans;
    	}
    }bit;
    
    struct LCT
    {
    	int val[N],minv[N],ch[N][2],fa[N];
    	bool rev[N];
    	
    	bool pos(int x) { return x==ch[fa[x]][1]; }
    	bool notrt(int x) { return x==ch[fa[x]][0] || x==ch[fa[x]][1]; }
    	
    	void pushup(int x)
    	{
    		minv[x]=min(val[x],min(minv[ch[x][0]],minv[ch[x][1]]));
    	}
    	
    	void pushdown(int x)
    	{
    		if (rev[x])
    		{
    			int lc=ch[x][0],rc=ch[x][1];
    			swap(ch[lc][0],ch[lc][1]); rev[lc]^=1;
    			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 splay(int x)
    	{
    		stack<int> st; st.push(x);
    		for (int i=x;notrt(i);i=fa[i]) st.push(fa[i]);
    		for (;st.size();st.pop()) pushdown(st.top());
    		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);
    		swap(ch[x][0],ch[x][1]); rev[x]^=1;
    	}
    	
    	void split(int x,int y)
    	{
    		makert(x); access(y);
    		splay(y);
    	}
    	
    	void link(int x,int y)
    	{
    		makert(x); fa[x]=y;
    		pushup(y);
    	}
    	
    	void cut(int x,int y)
    	{
    		makert(x); access(y); splay(y);
    		ch[y][0]=fa[x]=0;
    		pushup(x); pushup(y);
    	}
    }lct;
    
    int main()
    {
    	freopen("graph.in","r",stdin);
    	freopen("graph.out","w",stdout);
    	scanf("%d%d%d",&n,&m,&Q);
    	for (int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&U[i],&V[i]);
    		U[i]+=m; V[i]+=m;
    	}
    	for (int i=1;i<=Q;i++)
    	{
    		scanf("%d%d",&ask[i].l,&ask[i].r);
    		ask[i].id=i;
    	}
    	sort(ask+1,ask+1+Q,cmp);
    	for (int i=1;i<=n+m;i++)
    		father[i]=i,lct.val[i]=lct.minv[i]=i;
    	lct.minv[0]=2e9;
    	for (int i=1,j=1;i<=Q;i++)
    	{
    		for (;j<=ask[i].r;j++)
    		{
    			if (U[j]==V[j]) continue;
    			int x=find(U[j]),y=find(V[j]);
    			if (x==y)
    			{
    				lct.split(U[j],V[j]);
    				int p=lct.minv[V[j]];
    				lct.cut(p,U[p]); lct.cut(p,V[p]);
    				bit.add(p,-1);
    			}
    			else father[x]=y;
    			lct.link(j,U[j]); lct.link(j,V[j]);
    			bit.add(j,1);
    		}
    		int cnt=bit.query(m)-bit.query(ask[i].l-1);
    		ans[ask[i].id]=n-cnt;
    	}
    	for (int i=1;i<=Q;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    我的shell脚本
    Shell中[]里面的条件判断
    编写shell脚本需要特别关注的注意点
    Excel文本获取拼音
    netsh wlan start hostednetwork
    windows cmd 看服务cpu、内存
    cmd cvf war包
    PLSQL查询最近编绎、创建、修改过的过程函数
    根据sid或sqlID查询SQL
    JS字符串类型转日期然后进行日期比较
  • 原文地址:https://www.cnblogs.com/stoorz/p/14456316.html
Copyright © 2011-2022 走看看