1. 程式人生 > >2018.11.04-3988-地理課(geography)

2018.11.04-3988-地理課(geography)

地理 for size char nbsp 離線 技術 b- insert

題目描述:

地理課上,老師給出了一個巨大的地圖,由於世界日新月異,會有一些道路在某一時刻被刪除,也會有一些道路在某一時刻被修建。這裏的道路均為雙向的。

老師認為,有一些城市被分在了一個連通塊中可以相互到達,而有一些城市不能夠相互到達。而他想知道,每個時刻所有連通塊大小的乘積是多少?

wzy看到這個地圖的時候就蒙了,還好那只上天的喵及時幫助了他。現在他把這個毒瘤的地圖拿過來給你,想試試看你能不能求出來。由於答案可能很大,輸出乘積mod109+7即可。

輸入:

第一行兩個數n,m,表示有n個點,m個時刻。接下來m行每行三個數,要麽是1uv,要麽是2uv,分別表示添加一條無向邊和刪除一條無向邊。

輸出:

共m,每行一個數表示連通塊大小乘積mod1,000,000,007

數據範圍:

subtask1:30pts,n≤1,000,m≤2,000

subtask2:20pts,滿足沒有刪除操作。

subtask3:50pts,n,m≤100,000保證沒有重邊自環,不會刪除不存在的邊。

算法標簽:線段樹

思路:

這題是離線算法,因為對於一條邊有加入和刪除的操作,所以一條邊存在的時間是一段區間,把這段區間存入線段樹,每次層層修改,關鍵是返回時要怎麽回到這層的初始狀態。首先是在並查集的時候不能路徑壓縮,然後每次記錄下這層修改過的值,然後運用啟發式合並,所以效率期望是log(nlog2n)。

以下代碼:

技術分享圖片
#include<bits/stdc++.h>
#define
il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int p=1e9+7,N=1000000; int n,m,fa[N];int res[N],ny[N],sz[N]; struct data{int l,r,op;}t[N+5]; struct node{int x,x1,num;}; map<LL,int> ma;vector<LL> b[N<<2];vector<node> v[N<<2
]; il int read(){int x,f=1;char ch;_(!)ch==-?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;} il int getfa(int x){if(fa[x]==x)return x;return getfa(fa[x]);} il int ksm(int a,int y){int b=1;while(y){if(y&1)b=(LL)b*(LL)a%p;a=(LL)a*(LL)a%p;y>>=1;}return b;} il void insert(int x,int l,int r,int ql,int qr,LL v){ if(ql<=l&&r<=qr){ b[x].push_back(v); return; } int mid=(l+r)>>1; if(ql<=mid)insert(x<<1,l,mid,ql,qr,v); if(mid<qr)insert(x<<1|1,mid+1,r,ql,qr,v); } void work(int x,int l,int r,int sum){ if(l==r){ int tmp=sum; for(int i=0;i<b[x].size();i++){ LL kk=b[x][i]; int a,b1;a=(int)(kk/N);b1=(int)(kk%N); a=getfa(a);b1=getfa(b1);if(a==b1)continue; if(sz[a]<sz[b1])swap(a,b1); fa[b1]=a; tmp=(LL)tmp*(LL)ny[sz[a]]%p*(LL)ny[sz[b1]]%p; v[x].push_back((node){a,b1,sz[a]});sz[a]+=sz[b1]; tmp=(LL)tmp*(LL)sz[a]%p; } res[l]=tmp;printf("%d\n",tmp); for(int i=v[x].size()-1;i>=0;i--){ int kk=v[x][i].x;int ss=v[x][i].num; int k1=v[x][i].x1; fa[k1]=k1;sz[kk]=ss; } return; } int mid=(l+r)>>1;int tmp=sum; for(int i=0;i<b[x].size();i++){ LL kk=b[x][i]; int a,b1;a=(int)(kk/N);b1=(int)(kk%N); a=getfa(a);b1=getfa(b1);if(a==b1)continue; if(sz[a]<sz[b1])swap(a,b1); fa[b1]=a; tmp=(LL)tmp*(LL)ny[sz[a]]%p*(LL)ny[sz[b1]]%p; v[x].push_back((node){a,b1,sz[a]});sz[a]+=sz[b1]; tmp=(LL)tmp*(LL)sz[a]%p; } work(x<<1,l,mid,tmp);work(x<<1|1,mid+1,r,tmp); for(int i=v[x].size()-1;i>=0;i--){ int kk=v[x][i].x;int ss=v[x][i].num; int k1=v[x][i].x1; fa[k1]=k1;sz[kk]=ss; } } int main() { n=read();m=read();ny[1]=1;for(int i=2;i<=n;i++)ny[i]=ksm(i,p-2); for(int i=1;i<=m;i++){ t[i].op=read(); int x=read(),y=read(); if(x>y)swap(x,y); t[i].l=x;t[i].r=y; LL kk=(LL)x*(LL)N+y; if(ma[kk]==0)ma[kk]=i; else{ insert(1,1,m,ma[kk],i-1,kk); ma[kk]=0; } } for(int i=1;i<=m;i++){ if(t[i].op==1){ int x=t[i].l,y=t[i].r; LL kk=(LL)x*(LL)N+y; if(ma[kk]>0){ insert(1,1,m,ma[kk],m,kk),ma[kk]=0; } } } for(int i=1;i<=n;i++)sz[i]=1,fa[i]=i; work(1,1,m,1); return 0; }
View Code

此代碼跑了30s,慢的一b,僅供參考把

2018.11.04-3988-地理課(geography)