zoukankan      html  css  js  c++  java
  • 【CF1416D】Graph and Queries

    题目

    题目链接:https://codeforces.com/problemset/problem/1416/D
    给定一个 (n) 个点 (m) 条边的无向图,第 (i) 个点的点权初始值为 (p_i),所有 (p_i) 互不相同。
    接下来进行 (q) 次操作,分为两类:

    • ( t 1 v) 查询与 (v) 连通的点中, (p_u) 最大的点 (u) 并输出 (p_u),然后让 (p_u=0)
    • ( t 2 i) 将第 (i) 条边删掉。

    (nleq 2 imes 10^5,mleq 3 imes 10^5,Qleq 5 imes 10^5)

    思路

    我会线段树分治 + 左偏树!
    看到删边自然想到时间倒流变为加边,但是时间倒流后操作 (1) 的顺序就错了。
    把一条边的权值设为这条边删除之前,有多少次询问操作。求出这张图的 Kruskal 重构树,这样处理之后,对于任意一个点 (x),它第 (k) 次询问时可以到达的点一定是重构树上 (x) 某一个祖先的子树。
    可以通过倍增找到这一个点,然后问题转化为单点修改,子树求最大值,线段树维护即可。
    时间复杂度 (O(Qlog n))

    代码

    #include <bits/stdc++.h>
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    
    const int N=800010,LG=20;
    int n,m,Q,Q1,tot,head[N],a[N],b[N],father[N],id[N],siz[N],f[N][LG+1];
    
    struct node
    {
    	int u,v,t;
    }rd[N];
    
    bool cmp(node x,node y)
    {
    	return x.t<y.t;
    }
    
    struct edge
    {
    	int next,to;
    }e[N];
    
    void add(int from,int to)
    {
    	e[++tot]=(edge){head[from],to};
    	head[from]=tot;
    }
    
    int find(int x)
    {
    	return x==father[x]?x:father[x]=find(father[x]);
    }
    
    void dfs(int x,int fa)
    {
    	f[x][0]=fa; id[x]=++tot; siz[x]=1;
    	for (int i=1;i<=LG;i++)
    		f[x][i]=f[f[x][i-1]][i-1];
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (v!=fa) dfs(v,x),siz[x]+=siz[v];
    	}
    }
    
    struct SegTree
    {
    	pair<int,int> maxn[N*4];
    	
    	void update(int x,int l,int r,int k,int v)
    	{
    		if (l==r) { maxn[x]=mp(v,l); return; }
    		int mid=(l+r)>>1;
    		if (k<=mid) update(x*2,l,mid,k,v);
    			else update(x*2+1,mid+1,r,k,v);
    		maxn[x]=max(maxn[x*2],maxn[x*2+1]);
    	}
    	
    	pair<int,int> query(int x,int l,int r,int ql,int qr)
    	{
    		if (ql<=l && qr>=r) return maxn[x];
    		int mid=(l+r)>>1; pair<int,int> res=mp(0,0);
    		if (ql<=mid) res=max(res,query(x*2,l,mid,ql,qr));
    		if (qr>mid) res=max(res,query(x*2+1,mid+1,r,ql,qr));
    		return res;
    	}
    }seg;
    
    int main()
    {
    //	freopen("data.txt","r",stdin);
    	memset(head,-1,sizeof(head));
    	scanf("%d%d%d",&n,&m,&Q1);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	for (int i=1;i<=m;i++)
    		scanf("%d%d",&rd[i].u,&rd[i].v);
    	tot=n;
    	for (int i=1,opt,x;i<=Q1;i++)
    	{
    		scanf("%d%d",&opt,&x);
    		if (opt==1) b[++Q]=x;
    		if (opt==2) rd[x].t=++tot,a[tot]=Q;
    	}
    	for (int i=1;i<=m;i++)
    		if (!rd[i].t) rd[i].t=++tot,a[tot]=Q;
    	for (int i=1;i<=tot;i++) father[i]=i;
    	sort(rd+1,rd+1+m,cmp);
    	tot=0;
    	for (int i=m;i>=1;i--)
    	{
    		int x=find(rd[i].u),y=find(rd[i].v);
    		if (x!=y)
    		{
    			add(rd[i].t,x); add(rd[i].t,y);
    			father[x]=father[y]=rd[i].t;
    		}
    	}
    	tot=0;
    	for (int i=1;i<=n;i++)
    		if (!id[find(i)]) dfs(find(i),0);
    	for (int i=1;i<=n;i++)
    		seg.update(1,1,tot,id[i],a[i]);
    	for (int i=1;i<=Q;i++)
    	{
    		int x=b[i];
    		for (int j=LG;j>=0;j--)
    			if (a[f[x][j]]>=i) x=f[x][j];
    		pair<int,int> ans=seg.query(1,1,tot,id[x],id[x]+siz[x]-1);
    		cout<<ans.fi<<"
    ";
    		if (ans.fi) seg.update(1,1,tot,ans.se,0);
    	}
    	return 0;
    }
    
  • 相关阅读:
    【UNR#3】白鸽
    【POI2011】Garbage
    【NOI2010】海拔
    【HNOI2012】矿场搭建
    【UOJ#177】欧拉回路
    【BZOJ4500】矩阵
    【CF429E】Points and Segments
    【agc001F】Wide Swap
    【BZOJ2138】stone
    【JSOI2009】游戏
  • 原文地址:https://www.cnblogs.com/stoorz/p/15171513.html
Copyright © 2011-2022 走看看