题目描述
地理课上,老师给出了一个巨大的地图,由于世界日新月异,会有一些道路在某一时刻被删除,也会有一些道路在某一时刻被修建。这里的道路均为双向的。
老师认为,有一些城市被分在了一个连通块中可以相互到达,而有一些城市不能够相互到达。而他想知道,每个时刻所有连通块大小的乘积是多少?
wzy看到这个地图的时候就蒙了,还好那只上天的喵及时帮助了他。现在他把这个毒瘤的地图拿过来给你,想试试看你能不能求出来。由于答案可能很大,输出乘积mod109+7mod109+7即可。
输入
第一行两个数n,mn,m,表示有nn个点,mm个时刻。接下来mm行每行三个数,要么是1uv1uv,要么是2uv2uv,分别表示添加一条无向边和删除一条无向边。
输出
共mm,每行一个数表示连通块大小乘积mod1,000,000,007mod1,000,000,007
样例输入
<span style="color:#333333"><span style="color:#333333">样例输入#1
5 6
1 1 3
1 2 3
1 1 2
1 4 5
1 3 4
2 3 4
样例输入#2(对应subtask1)
见example\geography\geography2.in
样例输入#3(对应subtask2)
见example\geography\geography3.in
</span></span>
样例输出
<span style="color:#333333"><span style="color:#333333">样例输出#1
2
3
3
6
5
6
样例输出#2
见example\geography\geography2.out
样例输出#3
见example\geography\geography3.out
</span></span>
提示
上面是每个时刻操作后的图。乘积分别为:
2*1*1*1=2,3*1*1=3,3*1*1=3,3*2=6,5,3*2=6
数据范围及约定
subtask1:30pts,n≤1,000,m≤2,000n≤1,000,m≤2,000
subtask2:20pts,满足没有删除操作。
subtask3:50pts,n,m≤100,000n,m≤100,000保证没有重边自环,不会删除不存在的边。
题解:每一条边都会存在一段时间,所以我们可以给每一条边一个编号,在线段树上进行覆盖。
而答案就是每一个叶子结点的答案。
所以我们可以用可退还的并查集统计答案。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
#define mod 1000000007
using namespace std;
typedef long long ll;
struct Node{int opt,x,y;}s[100005];
int n,m,par[100005],si[100005],cnt,las[100005];
int prex[100005],prey[100005],top[30];
struct xx{int x,y,z;}zh[30][100005];
ll ans=1,ny[100005];
struct node
{
int l,r;
vector<int>v;
}tree[400005];
map<int,int>dy[100005];
int find(int x)
{
if(par[x]!=x)return find(par[x]);
return x;
}
void build(int k,int l,int r)
{
tree[k].l=l;tree[k].r=r;
if(l==r)return;
int mid=l+r>>1;
build(k*2,l,mid);build(k*2+1,mid+1,r);
}
void update(int k,int l,int r,int t)
{
if(l<=tree[k].l&&r>=tree[k].r){tree[k].v.push_back(t);return;}
int mid=tree[k].l+tree[k].r>>1;
if(l<=mid)update(k*2,l,r,t);
if(r>mid)update(k*2+1,l,r,t);
}
ll ksm(int x)
{
int y=mod-2;ll sum=1;
while(y)
{
if(y&1)sum=(ll)sum*x%mod;
x=(ll)x*x%mod;y>>=1;
}
return sum;
}
void solve(int k,int p)
{
ll lans=ans;
for(int i=0;i<tree[k].v.size();++i)
{
int x=prex[tree[k].v[i]],y=prey[tree[k].v[i]];
int f1=find(x),f2=find(y);
if(f1!=f2)
{
ans=(ll)ans*ny[si[f1]]%mod*ny[si[f2]]%mod*(si[f1]+si[f2])%mod;
if(si[f1]>si[f2])
{
zh[p][++top[p]]=(xx){f2,f1,si[f2]};
si[f1]+=si[f2];par[f2]=f1;
}
else
{
zh[p][++top[p]]=(xx){f1,f2,si[f1]};
si[f2]+=si[f1];par[f1]=f2;
}
}
}
if(tree[k].l==tree[k].r)printf("%lld\n",ans);
else solve(k*2,p+1),solve(k*2+1,p+1);
for(int i=top[p];i>=1;--i)
{
si[zh[p][i].x]=zh[p][i].z;par[zh[p][i].x]=zh[p][i].x;
si[zh[p][i].y]-=zh[p][i].z;
}
ans=lans;top[p]=0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&s[i].opt,&s[i].x,&s[i].y);
if(s[i].x>s[i].y)swap(s[i].x,s[i].y);
if(!dy[s[i].x][s[i].y])
dy[s[i].x][s[i].y]=++cnt,prex[cnt]=s[i].x,prey[cnt]=s[i].y;
}
build(1,1,m);
for(int i=1,u;i<=m;++i)
{
u=dy[s[i].x][s[i].y];
if(s[i].opt==1)las[u]=i;
else update(1,las[u],i-1,u),las[u]=0;
}
for(int i=1,u;i<=m;++i)
{
u=dy[s[i].x][s[i].y];
if(las[u])update(1,las[u],m,u),las[u]=0;
}
for(int i=1;i<=n;++i)par[i]=i,si[i]=1,ny[i]=ksm(i);
solve(1,1);
}