【题解】P5163 WD与地图 (这题极好)
【题解】P5163 WD与地图 (这题极好)
题目大意
初始有一个有向图,现在要你支持以下操作
- 删除一条边
- 把一个点点权修改下
- 输出一个点所在的SCC的最大k个点权和
\(n\le 1e5,m,q \le 2e5,\)
删边不好处理,先时间倒流下,问题变成了支持加入一条边。
如果图是无向图,这题就很好做(并查集+treap/线段树合并),因为每条边都把两个端点立马变成了一个SCC了。而有向图难处理就难在可能很多条边会在最后一条关键边加入时,同时使得很多点变成一个SCC。
考虑我们让"很多边"和"关键边"同时加入,这样显然是不影响答案的(SCC没有改变)。
图的连通性是满足二分性的,考虑对于每条边,二分出这样一个最早时刻\(t\),使得这条边的两个端点在一个SCC里。然后我们在\(t\)时刻时把这条边当做无向边加入。
这样的复杂度无法接受,然而多个元素共用一个\(\rm{check}\)可以整体二分。可撤销并查集维护SCC即可。
得到这些之后,再套用无向图的做法即可
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std; typedef long long ll;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c)) f|=c==45,c=getchar();
while( isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=2e5+5;
int n,m,q,w[maxn],T[maxn],usd[maxn],len;
pair<int,int> e[maxn];
struct{int op,a,b;}que[maxn];
ll ans[maxn];
vector<int>sav;
int getVal(int x){
return lower_bound(sav.begin(),sav.end(),x)-sav.begin();
}
namespace getTime{
namespace BCJ{
int r[maxn],siz[maxn],stk[maxn],top;
int Find(int x){return x==r[x]?x:Find(r[x]);}
int Merge(int x,int y){
x=Find(x),y=Find(y);
if(x==y) return 0;
if(siz[x]>siz[y]) swap(x,y);
r[x]=y; siz[y]+=siz[x]; stk[++top]=x;
return 1;
}
void Undo(int cnt){
int temp;
while(cnt-->0&&top)
temp=stk[top--],siz[r[temp]]-=siz[temp],r[temp]=temp;
}
void init(){for(int t=1;t<=n;++t)r[t]=t,siz[t]=1;}
}using namespace BCJ;
namespace Tarjan{
vector<int>e[maxn],ve;
int dfn[maxn],low[maxn],T,stk[maxn],in[maxn],top,cnt;
void add(int fr,int to){
if(fr==to) return;
ve.push_back(fr); ve.push_back(to);
e[fr].push_back(to);
}
void clear(){
for(auto t:ve) e[t].clear(),dfn[t]=low[t]=0;
ve.clear(); T=0; cnt=0;
}
void dfs(int now){
dfn[now]=low[now]=++T; stk[++top]=now; in[now]=1;
for(auto t:e[now]){
if(!dfn[t]) dfs(t),low[now]=min(low[now],low[t]);
if(dfn[t]&&in[t]) low[now]=min(low[now],dfn[t]);
}
if(low[now]==dfn[now]){
int temp;
do
cnt+=Merge(temp=stk[top--],now),in[temp]=0;
while(temp!=now);
}
}
int init(){
for(auto t:ve)
if(!dfn[t])
dfs(t);
return cnt;
}
}
vector<pair<int,int>> getEdge(int l,int r){
vector< pair<int,int> > ret;
if(l==0){
for(int t=1;t<=m;++t)
if(!usd[t])
ret.push_back(e[t]);
}
for(int t=l;t<=r;++t)
if(que[t].op==1)
ret.push_back({que[t].a,que[t].b});
return ret;
}
void solve(int l,int r,vector<int>E){
if(l>=r||E.empty()){
for(auto t:E) T[t]=l;
return;
}
int mid=(l+r)>>1,cnt=0;
Tarjan::clear();
for(auto t:E)
if(usd[t]<=mid)
Tarjan::add(Find(e[t].first),Find(e[t].second));
cnt=Tarjan::init();
vector<int>lef,rgt;
for(auto t:E)
if(Find(e[t].first)==Find(e[t].second)&&usd[t]<=mid)
lef.push_back(t);
else rgt.push_back(t);
solve(mid+1,r,rgt);
Undo(cnt);
solve(l,mid,lef);
}
void init(){
BCJ::init();
vector<int>ve;
for(int t=1;t<=m;++t) ve.push_back(t);
solve(0,q+1,ve);
}
}
namespace getAns{
struct EDGE{
int u,v,T;
bool operator < (EDGE x)const{return T<x.T;}
}edge[maxn];
struct NODE{
int ls,rs,val,cnt,siz;
}seg[maxn<<6];
ll sum[maxn<<6];
int cnt,r[maxn],rt[maxn];
void pp(int pos){
seg[pos].siz=seg[pos].cnt+seg[seg[pos].ls].siz+seg[seg[pos].rs].siz;
sum[pos]=sum[seg[pos].ls]+sum[seg[pos].rs]+1ll*seg[pos].val*seg[pos].cnt;
}
#define mid ((l+r)>>1)
#define lef l,mid,seg[pos].ls
#define rgt mid+1,r,seg[pos].rs
void build(int p,int l,int r,int&pos){
if(l>p||r<p) return;
if(!pos) pos=++cnt;
if(l==r) return sum[pos]=sav[p],seg[pos].val=sav[p],seg[pos].cnt=seg[pos].siz=1,void();
if(p<=mid) build(p,lef);
if(p>mid) build(p,rgt);
pp(pos);
}
void upd(int p,int delta,int l,int r,int&pos){
if(p<l||r<p) return;
if(!pos) pos=++cnt;
if(l==r){
seg[pos].cnt+=delta; seg[pos].siz+=delta;
seg[pos].val=sav[p];
sum[pos]=1ll*seg[pos].cnt*seg[pos].val;
return;
}
if(p<=mid) upd(p,delta,lef);
else upd(p,delta,rgt);
pp(pos);
}
int Merge(int l,int r,int t1,int t2){
if(!t1||!t2) return t1|t2;
if(t1==t2) cerr<<"Merge_same"<<t1<<endl;
if(seg[t1].val!=seg[t2].val) return cerr<<"wrong value!"<<endl,0;
seg[t1].cnt+=seg[t2].cnt;
seg[t1].siz+=seg[t2].siz;
seg[t1].ls=Merge(l,mid,seg[t1].ls,seg[t2].ls);
seg[t1].rs=Merge(mid+1,r,seg[t1].rs,seg[t2].rs);
pp(t1);
return t1;
}
ll sumK(int k,int l,int r,int pos){
if(!pos||!k) return 0;
if(l==r) return 1ll*seg[pos].val*min(seg[pos].cnt,k);
if(k>=seg[seg[pos].rs].siz) return sum[seg[pos].rs]+sumK(k-seg[seg[pos].rs].siz,lef);
return sumK(k,rgt);
}
int Find(int x){return x==r[x]?x:r[x]=Find(r[x]);}
#undef mid
#undef lef
#undef rgt
void Merge(int u,int v){
u=Find(u); v=Find(v);
if(u==v) return;
rt[v]=rt[u]=Merge(1,len,rt[u],rt[v]);
r[u]=v;
}
void init(){
cnt=n;
for(int t=1;t<=n;++t) build(getVal(w[t]),1,len,rt[t]),r[t]=t;
for(int t=1;t<=m;++t)
edge[t]={e[t].first,e[t].second,T[t]};
sort(edge+1,edge+m+1);
for(int t=1,j=0;t<=q;++t){
if(que[t].op==1) continue;
while(j+1<=m&&edge[j+1].T<=t) ++j,Merge(edge[j].u,edge[j].v);
if(que[t].op==2)
upd(getVal(w[que[t].a]),-1,1,len,rt[Find(que[t].a)]),w[que[t].a]-=que[t].b,upd(getVal(w[que[t].a]),1,1,len,rt[Find(que[t].a)]);
if(que[t].op==3) ans[t]=sumK(que[t].b,1,len,rt[Find(que[t].a)]);
}
}
}
signed main(){
n=qr(); m=qr(); q=qr();
for(int t=1;t<=n;++t) w[t]=qr(),sav.push_back(w[t]);
for(int t=1;t<=m;++t) e[t].first=qr(),e[t].second=qr();
sort(e+1,e+m+1);
for(int t=1;t<=q;++t) {
que[t].op=qr(),que[t].a=qr(),que[t].b=qr();
if(que[t].op==2) w[que[t].a]+=que[t].b,sav.push_back(w[que[t].a]);
}
reverse(que+1,que+q+1);
for(int t=1;t<=q;++t){
if(que[t].op==1) usd[lower_bound(e+1,e+m+1,(pair<int,int>){que[t].a,que[t].b})-e]=t;
}
sav.push_back(-1);
sort(sav.begin(),sav.end());
sav.resize(unique(sav.begin(),sav.end())-sav.begin());
len=sav.size()-1;
getTime::init();
getAns::init();
for(int t=1;t<=q;++t)
if(que[q-t+1].op==3)
printf("%lld\n",ans[q-t+1]);
return 0;
}
博客保留所有权利,谢绝学步园、码迷等不在文首明显处显著标明转载来源的任何个人或组织进行转载!其他文明转载授权且欢迎!