不提供链接
题目描述
题解
考虑对询问分块,在数组里存下最近的最多 B L = n BL=\sqrt{n} BL=n 次1操作,若数组满了就把操作拿出来一块处理。由于前面的操作不能作用于后面的操作,所以我们从后往前暴力地处理操作,规定一个点只能访问一次,总共是 O ( n ) O(n) O(n) 的。
对于操作2,显然只有某节点最后一次操作1之后的才有效。我们同样对询问分块,在每个块内的操作2,我们按值从小到大暴力处理,同样是 O ( n ) O(n) O(n) 的。
对于询问,我们可以先求出最后一次覆盖的操作1的时间,然后询问后面的操作2,用整块直接访问、边角暴力判断即可。
剩下的问题是,我们需要每次 O ( 1 ) O(1) O(1) 地判断某个点能否到达询问点,这很容易想到用 B i t s e t Bitset Bitset。但是直接的 B i t s e t Bitset Bitset 时间空间都是 O ( n 2 w ) O(\frac{n^2}{w}) O(wn2) 的,根本过不了。我们先考虑怎么降下空间:再对询问分个块,每次对块长这么多个询问点一起做一次拓扑+ B i t s e t Bitset Bitset,那么 B i t s e t Bitset Bitset 的大小只用开到块长。
此时的总时间是
O
(
n
∗
询
问
个
数
w
+
q
n
)
O(\frac{n*询问个数}{w}+q\sqrt{n})
O(wn∗询问个数+qn)
还是一副不可过的样子,但是由于最大数据要保证操作数都十分充足,导致询问数很少(好像只有大约
n
10
\frac{n}{10}
10n)的样子,所以卡卡就过了。
代码
#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define uns unsigned
#define IF (it->first)
#define IS (it->second)
#define END putchar('\n')
using namespace std;
const int MAXN=100005;
const ll INF=1e17;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
return f?x:-x;
}
int ptf[50],lpt;
inline void print(ll x,char c='\n'){
if(x<0)putchar('-'),x=-x;
ptf[lpt=1]=x%10;
while(x>9)x/=10,ptf[++lpt]=x%10;
while(lpt)putchar(ptf[lpt--]^48);
if(c>0)putchar(c);
}
inline ll lowbit(ll x){return x&-x;}
const int M=64,B=4096;
struct BS{
uns ll a[M];BS(){}
BS(int x){memset(a,0,sizeof(a)),a[x/M]|=(1ull<<x%M);}
inline bool AT(int x){return (a[x/M]>>x%M)&1;}
inline BS operator|(const BS&b)const{
BS res;
for(int i=0;i<M;i++)res.a[i]=a[i]|b.a[i];
return res;
}
}EM,b[MAXN];
struct itn{
int op,x;ll d;itn(){}
itn(int O,int X,ll D){op=O,x=X,d=D;}
}st[MAXN],ts[MAXN],q2[MAXN];
int n,m,Q,le,el;
struct edge{
int v,to;edge(){}
edge(int V,int T){v=V,to=T;}
}e[MAXN<<1];
int EN,G[MAXN],D[MAXN],du[MAXN];
inline void addedge(int u,int v){
e[++EN]=edge(v,G[u]),G[u]=EN;
e[++EN]=edge(u,D[v]),D[v]=EN;
}
queue<int>q;
int dfn[MAXN],la[MAXN],id[MAXN],IN;
ll val[MAXN],bv[320][MAXN];
vector<itn>q1[MAXN];
inline void solve(int l){
IN=0;
for(int i=1;i<=n;i++)id[i]=0;
for(int i=l;i<=Q&&IN<B;i++)
if(q2[i].op==3&&!id[q2[i].x])id[q2[i].x]=++IN;
for(int i=1;i<=n;i++){
du[i]=0;
if(id[i]>0)b[i]=BS(id[i]-1);
else b[i]=EM;
}
if(!IN)return;
for(int i=2;i<=EN;i+=2)du[e[i].v]++;
for(int i=1;i<=n;i++)if(!du[i])q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=D[u];i;i=e[i].to){
int v=e[i].v;
b[v]=b[v]|b[u],du[v]--;
if(!du[v])q.push(v);
}
}
}
inline bool rec(int x,int y){
if(!id[y])return 0;
return b[x].AT(id[y]-1);
}
signed main()
{
freopen("dag.in","r",stdin);
freopen("dag.out","w",stdout);
n=read(),m=read(),Q=read();
for(int i=1,u,v;i<=m;i++)u=read(),v=read(),addedge(u,v);
int BL=316;
for(int i=1;i<=Q;i++){
q2[i].op=read(),q2[i].x=read();
if(q2[i].op<3)q2[i].d=read();
}
solve(1);
for(int fn=1;fn<=Q;fn++){
int op=q2[fn].op,x=q2[fn].x;q2[fn].x=0;
if(op==1)st[++le]=itn(fn,x,q2[fn].d);
else if(op==2)ts[++el]=itn(fn,x,q2[fn].d),q2[fn]=ts[el];
else{
ll ans=val[x];
for(int i=1;i<=le;i++)if(rec(st[i].x,x))
ans=st[i].d,la[x]=st[i].op;
for(int i=la[x];i<=fn;){
if(i%BL==0&&i-BL>=la[x])ans=min(ans,bv[(i-1)/BL][x]+INF);
else if(q2[i].x&&rec(q2[i].x,x))ans=min(ans,q2[i].d);
if(i%BL==0&&i+BL<=fn)i+=BL;
else i++;
}
print(ans);
}
if(fn<Q&&q2[fn+1].op==3&&!id[q2[fn+1].x])solve(fn+1);
if(fn%BL==0){
int x=(fn-1)/BL;
sort(ts+1,ts+1+el,[](itn a,itn b){return a.d<b.d;});
for(int i=1;i<=el;i++){
while(!q.empty())q.pop();
if(bv[x][ts[i].x]+INF>ts[i].d)
bv[x][ts[i].x]=ts[i].d-INF,q.push(ts[i].x);
while(!q.empty()){
int u=q.front();q.pop();
for(int j=G[u];j;j=e[j].to){
int v=e[j].v;
if(bv[x][v]+INF<=ts[i].d)continue;
bv[x][v]=ts[i].d-INF,q.push(v);
}
}
}el=0;
}
if(le<=BL)continue;
for(int i=1;i<=n;i++)dfn[i]=0;
for(int i=le;i>0;i--){
while(!q.empty())q.pop();
if(dfn[st[i].x]<i)dfn[st[i].x]=i,q.push(st[i].x);
while(!q.empty()){
int u=q.front();q.pop();
val[u]=st[i].d,la[u]=st[i].op;
for(int j=G[u];j;j=e[j].to){
int v=e[j].v;
if(dfn[v]>=i)continue;
dfn[v]=i,q.push(v);
}
}
}le=0;
}
return 0;
}