题目
题目链接: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;
}