【题解】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;
}


posted @ 2020-05-21 21:12  谁是鸽王  阅读(220)  评论(0编辑  收藏  举报