地理課(geography)
阿新 • • 發佈:2018-11-16
地理課(geography)
題目描述
地理課上,老師給出了一個巨大的地圖,由於世界日新月異,會有一些道路在某一時刻被刪除,也會有一些道路在某一時刻被修建。這裡的道路均為雙向的。
老師認為,有一些城市被分在了一個連通塊中可以相互到達,而有一些城市不能夠相互到達。而他想知道,每個時刻所有連通塊大小的乘積是多少?
wzy看到這個地圖的時候就蒙了,還好那隻上天的喵及時幫助了他。現在他把這個毒瘤的地圖拿過來給你,想試試看你能不能求出來。由於答案可能很大,輸出乘積mod109+7mod109+7即可。
輸入
第一行兩個數n,mn,m,表示有nn個點,mm個時刻。接下來mm行每行三個數,要麼是1uv1uv,要麼是2uv2uv,分別表示新增一條無向邊和刪除一條無向邊。
輸出
共mm,每行一個數表示連通塊大小乘積mod1,000,000,007mod1,000,000,007
上面是每個時刻操作後的圖。乘積分別為:
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保證沒有重邊自環,不會刪除不存在的邊。
來源
solution
好題好題
考慮離線,按時間建一棵線段樹
把每一個邊的編號加進線段樹對應的區間中
我們現在希望得到每一個葉子節點的值
那麼每次暴力求是不行了
我們記下每一層的邊連線的並查集的根與大小
返回時把邊拆開即可
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<map> #include<vector> #define mod 1000000007 #define maxn 100005 #define ll long long using namespace std; int n,m,f[maxn],sz[maxn],t1,t2,op; ll now,ans[maxn],ny[maxn]; struct node{ int u,v,st,ed; }e[maxn]; map<ll,int>ls; struct no{ int l,r; vector<int>x; }tree[maxn*8]; struct Node{ int id,x,y,size; }; vector<Node>p; 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 add(int k,int L,int R,int v){ //cout<<k<<' '<<L<<' '<<R<<''<<endl; if(tree[k].l>=L&&tree[k].r<=R){ tree[k].x.push_back(v);return; } int mid=tree[k].l+tree[k].r>>1; if(L<=mid)add(k*2,L,R,v); if(R>mid)add(k*2+1,L,R,v); } ll work(ll a,int num){ ll an=1; while(num){ if(num&1)an=an*a; a=a*a;a%=mod;an%=mod;num>>=1; } return an; } int getf(int k){ if(f[k]==k)return k; return getf(f[k]); } void hb(int k){ //cout<<"k: "<<k<<' '<<tree[k].l<<' '<<tree[k].r<<endl; for(int i=0;i<tree[k].x.size();i++){ int t=tree[k].x[i]; //cout<<t<<endl; int f1=getf(e[t].u),f2=getf(e[t].v); if(f1!=f2){ now=now*ny[sz[f1]]%mod*ny[sz[f2]]%mod; now=now*(sz[f1]+sz[f2])%mod; if(sz[f1]<sz[f2]){ p.push_back((Node){k,f1,f2,sz[f1]}); f[f1]=f2;sz[f2]+=sz[f1];sz[f1]=0; } else { p.push_back((Node){k,f2,f1,sz[f2]}); f[f2]=f1;sz[f1]+=sz[f2];sz[f2]=0; } } } } void turn(int k){ int Size=p.size()-1;if(Size<0)return; //cout<<"Size "<<Size<<' '<<tree[k].l<<' '<<tree[k].r<<endl; for(int i=Size;p[i].id==k&&i>=0;i--){ //cout<<p[i].x<<' '<<p[i].y<<' '<<sz[p[i].x]<<' '<<sz[p[i].y]<<endl; now=now*ny[sz[p[i].y]]%mod; f[p[i].x]=p[i].x;sz[p[i].x]=p[i].size;sz[p[i].y]-=sz[p[i].x]; now=now*sz[p[i].x]%mod*sz[p[i].y]%mod; p.pop_back(); } } void dfs(int k){ hb(k); if(tree[k].l==tree[k].r){ ans[tree[k].l]=now;turn(k); return; } dfs(k*2);dfs(k*2+1); turn(k); } int main() { cin>>n>>m; for(int i=1;i<=m;i++){ scanf("%d%d%d",&op,&e[i].u,&e[i].v); if(e[i].u>e[i].v)swap(e[i].u,e[i].v); ll tmp=(ll)e[i].u*100000+e[i].v; if(op==1){ls[tmp]=i;e[i].st=i;} else { int la=ls[tmp];e[la].ed=i-1; //ls[tmp]=0; } } build(1,1,m); for(int i=1;i<=m;i++){ if(e[i].ed==0)e[i].ed=m; if(e[i].st&&e[i].ed)add(1,e[i].st,e[i].ed,i); } for(int i=1;i<=n;i++)ny[i]=work(i,mod-2); for(int i=1;i<=n;i++)f[i]=i,sz[i]=1; now=1;dfs(1); for(int i=1;i<=m;i++)printf("%lld\n",ans[i]); return 0; }