題目大意
一幅有向圖有 個結點,初始沒有邊。
有 個操作,四種類型:
- :加入邊
- :加入邊
- :刪除邊
- :刪除邊
加邊之前會保證原來沒有這條邊,刪邊之前會保證原來有這條邊。
每次操作後,可以得到一個連通性矩陣 ( 表示 能到 ),輸出
3s
解法1
每個點維護一個 bitset 表示它能到哪些點。
每次操作時,暴力重構 的 bitset,然後 bfs 一下把能到 的點找出來,按拓撲序更新它們的 bitset。維護 bitset 時順便維護答案。
對於加邊操作的更新,是 。這個的時間主要在於圖的遍歷,邊表是 的,因此時間是 。
對於刪邊操作的更新,是 ( 表示 的出點),由於之前是或操作不可撤銷,因此這個要對於 枚舉它的出點重新算,因此是 。
因此總的時間是 ,算出來 8 億但是跑過去了。
解法2
上面的解法,加邊很優秀,但是刪邊不太行,這是因爲刪邊的時候由於維護的是“是否連通”,所以無法快速撤銷一個出點的影響。
那什麼可以撤銷呢?方案數就可以撤銷!
記 表示 走到 的方案數,給它模個 啥的(不放心就多模幾個)。
每次操作時,暴力重算 或者 ,然後對於所有 ,先 原來的,再 新的。
這樣就是 的了。
代碼
// 解法1
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef unsigned int uint;
const int maxn=405;
int n,q,len,x[maxn];
uint A[maxn],B[maxn];
bool mp[maxn][maxn];
bitset<maxn> a[maxn];
void ReadChar(char &ch)
{
ch=getchar();
while (ch!='+' && ch!='-' && ch!='o' && ch!='i') ch=getchar();
}
bool bz[maxn];
void dfs1(int k,int v)
{
if (v!=k) a[v][k]=1;
bz[k]=1;
fo(i,1,n) if (mp[k][i] && !bz[i]) dfs1(i,v);
}
int d[3*maxn],dg[maxn];
void topo(int v,char ty)
{
fo(i,1,n) bz[i]=0, dg[i]=0;
int j=0;
if (ty=='o') d[j=1]=v;
else fo(i,1,len) d[++j]=x[i];
for(int i=1; i<=j; i++)
{
fo(go,1,n) if (mp[go][d[i]])
{
dg[go]++;
if (!bz[go]) bz[ d[++j]=go ]=1;
}
}
}
uint ans,Ans[maxn];
void Redo(int v)
{
ans-=Ans[v];
Ans[v]=0;
fo(i,1,n) if (a[v][i]) Ans[v]+=A[v-1]*B[i-1];
ans+=Ans[v];
}
int main()
{
freopen("reachability.in","r",stdin);
freopen("reachability.out","w",stdout);
scanf("%d %d %u %u",&n,&q,&A[1],&B[1]);
A[0]=B[0]=1;
fo(i,2,n) A[i]=A[i-1]*A[1], B[i]=B[i-1]*B[1];
while (q--)
{
char ch1,ch2; int v;
ReadChar(ch1), ReadChar(ch2);
scanf("%d %d",&v,&len);
fo(i,1,len)
{
scanf("%d",&x[i]);
if (ch2=='o') mp[v][x[i]]^=1; else mp[x[i]][v]^=1;
}
if (ch2=='o')
{
a[v].reset();
fo(i,1,n) bz[i]=0;
dfs1(v,v);
Redo(v);
}
topo(v,ch2);
if (ch1=='+')
{
int j=0;
if (ch2=='o') d[j=1]=v;
else fo(i,1,len) d[++j]=x[i];
for(int i=1; i<=j; i++)
{
a[d[i]]|=a[v];
if (d[i]!=v) a[d[i]][v]=1;
Redo(d[i]);
fo(go,1,n) if (mp[go][d[i]])
{
if (--dg[go]==0) d[++j]=go;
}
}
} else
{
int j=0;
if (ch2=='o') d[j=1]=v;
else fo(i,1,len) d[++j]=x[i];
for(int i=1; i<=j; i++)
{
a[d[i]].reset();
fo(go,1,n) if (mp[d[i]][go]) a[d[i]]|=a[go], a[d[i]][go]=1;
Redo(d[i]);
fo(go,1,n) if (mp[go][d[i]])
{
if (--dg[go]==0) d[++j]=go;
}
}
}
printf("%u\n",ans);
}
}