• P5163 WD与地图——整体二分


    整体二分一类题目中的高端题

    如果不是有向图,这个题也就是个紫题水平。直接倒序加边,每个点维护一棵权值线段树,再用并查集判联通块即可……

    但是,它是有向图……

    这意味着我们根本不知道什么时候他会构成连通块。

    考虑每个有向边,对一条边连接的两个点来说,肯定有一个时刻它们不再在同一个连通块里,所以单个边考虑的话,只需要对序列二分判强连通就知道从什么时候开始它们不在同一个连通块里。

    然后发现了单个可以二分之后,就可以联想到对序列整体进行二分来求出每一个边的分离时间。

    之后求出每个分离时间之后,再按正常套路倒序加边,并查集维护连通块,线段树合并维护强连通第k大即可

    (没想到我人生中第一道线段树合并是这个题……

    detail:

    这个题的细节巨多,能恶心死你

    尤其是整体二分那块真的是看到就恶心

    还有,权值线段树开成值域范围,不要像我一样开成n的大小……

    线段树合并用指针真能把人气死 , 一个个特判看着就烦

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define int long long
    #define INF 1ll<<30
    #define pb push_back
    #define pii pair<int ,int >
    
    const int p=2e6+5;
    
    template<typename _T>
    inline void read(_T &x)
    {
    	x=0;char s=getchar();int f=1;
    	while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
    	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
    	x*=f;
    }
    struct Edge{
    	int u,v,tim;
    }e[p];
    
    map<pii,int> mapp; 
    int a[p],b[p*4] , bili;
    int n,m,q;
    struct node{
    	int opt , a, b , tim;
    }c[p*4];
    
    struct query{
    	int opt , a , b;
    }qa[p];
    
    struct segment{
    	struct tree{
    		int l,r;
    		tree *ls , *rs;
    		int cnt , sum;	
    		inline void pushup(){cnt = ls->cnt + rs->cnt,sum = ls->sum + rs->sum;}		
    		inline int query(int k)
    		{
    			if(!this) return 0;
    			if(cnt < k) return sum;
    			if(l == r) return k*b[l];
    			if(rs && k<=rs->cnt) return rs->query(k);
    			else return (rs?rs->sum:0 )+ ls->query(k - (rs?rs->cnt:0));
    		}	
    	}mem[p * 4],*pool = mem;
    	tree *rot[p];
    	inline tree *New(int L,int R){++pool;pool->l = L;pool->r = R;return pool;}
    
    	inline void update(tree *u,int pos,int add)
    	{
    		u->cnt+=add;
    		u->sum += add*b[pos];
    		if(u->l == u->r) return;
    		int mid = u->l + u->r >> 1;
    		int L = u->l , R = u->r;
    		if(pos <= mid) update((u->ls)?u->ls:(u->ls = New(L,mid)) , pos , add);
    		else update(u->rs?u->rs:(u->rs = New(mid+1,R)) , pos , add);
    	}
    	
    	inline void Merge(tree *a, tree *b)
    	{
    		if(!b) return;
    		else if(!a->sum&&!a->cnt){*a = *b;return;} 
    		if(a->l == a->r) {a->cnt += b->cnt , a->sum += b->sum ; return;}
    		else
    		{
    			int L = a->l , R = a->r , mid = L+R>>1;
    			Merge(a->ls?a->ls:a->ls = New(L,mid),b->ls);
    			Merge(a->rs?a->rs:a->rs = New(mid+1,R) , b->rs);
    			if(a->ls&&a->rs) a->pushup();
    			else{
    				if(a->ls) a->cnt = a->ls->cnt , a->sum = a->ls->sum;
    				else a->cnt = a->rs->cnt, a->sum = a->rs->sum; 
    			}
    		}
    	}
    	inline void merge(int x,int y) {Merge(rot[x] , rot[y]);}
    }segT;
    
    struct bcj{
    	Edge st[p];
    	int top;
    	int fa[p] , dep[p];
    	inline void Init(){for(int i=1;i<=n;i++) fa[i] = i , dep[i] = 1;}
    	inline int f(int x){while(x!=fa[x])x = fa[x];return fa[x];}
    	
    	inline void unite(int x,int y)
    	{
    		x = f(x) , y = f(y);
    		if(x == y) return;
    		else  
    		{
    			if(dep[x] < dep[y]) swap(x , y);
    			fa[y] = x;
    			st[++top] = {x , y ,dep[x] == dep[y]};
    			dep[x] += dep[y]==dep[x];
    		}
    	}
    	
    	inline void Del(int lim)
    	{
    		while(top>lim) 
    		{
    			int u = st[top].u,v = st[top].v;
    			int add = st[top].tim;
    			fa[v] = v;
    			dep[u] -= add;
    			top--;
    		}
    	}
    	
    	inline void Merge(int x,int y)
    	{
    		x = f(x) , y = f(y);
    		if(x == y) return;
    		else  
    		{
    			if(dep[x] < dep[y]) swap(x , y);
    			fa[y] = x;
    			dep[x] += dep[y]==dep[x];
    			segT.merge(x , y);
    		}
    	}
    	
    }s,s1;
    
    struct shp{
    	int dfn[p] , low[p];
    	int head[p],nxt[p],ver[p],tit;
    	int top , st[p] , lim,vis[p];
    	
    	inline void add(int x,int y)
    	{
    		ver[++tit] = y;
    		nxt[tit] = head[x];
    		head[x] = tit;
    	}
    	inline void tarjan(int x)
    	{
    		dfn[x] = low[x] = ++lim;
    		vis[x] = 1;st[++top] = x;
    		for(int i=head[x] ;i;i =nxt[i])
    		{
    			int v = ver[i];
    			if(!dfn[v]) tarjan(v) , low[x] = min(low[x] , low[v]);
    			else if(vis[v]) low[x] = min(dfn[v] , low[x]);
    		}
    		if(dfn[x] == low[x])
    		{
    			int now = st[top--];
    			vis[now] = 0;
    			while(st[top + 1]!=x)
    			{
    				vis[st[top]] = 0;
    				s.unite(now , st[top--]);
    			}
    		}
    	}
    	
    	inline void solve(vector<int> x){for(auto i:x)if(!dfn[i]) tarjan(i);}
    	inline void clear(vector<int> x){for(auto i:x) head[i] = low[i] = dfn[i] = 0;lim = tit = 0;}
    }Tarjan;
    
    Edge lef[p],rig[p];
    int Tl,Tr; 
    vector<int> vec;
    
    inline void solve(int vl,int vr,int l,int r)
    {
    	if(l>r) return;
    	if(vl == vr)
    	{
    		for(int i=l;i<=r;i++) e[i].tim = vl;
    		return;
    	}
    	int mid = vl + vr >>1;
    	vec.clear();
    	int lim = s.top;
    	for(int i=l;i<=r;i++)
    	{
    		int u = e[i].u , v = e[i].v;
    		int r1 = s.f(u) , r2 = s.f(v);
    		int tim = e[i].tim;
    		if(tim <= mid) Tarjan.add(r1,r2),vec.pb(r1) , vec.pb(r2);
    	}
    	Tarjan.solve(vec);
    	Tl = Tr = 0;
    	for(int i=l;i<=r;i++)
    	{
    		int u = e[i].u , v = e[i].v;
    		int tim = e[i].tim;
    		int r1 = s.f(u) , r2 = s.f(v);
    		if(r1 != r2 || tim > mid) rig[++Tr] = e[i];
    		else lef[++Tl] = e[i];		
    	}
    	for(int i=l;i<=l+Tl - 1;i++)
    	{
    		e[i] = lef[i - l + 1];
    	 } 
    	for(int i=l+Tl;i<=r;i++)
    	{
    		e[i] = rig[i - (l + Tl - 1)];
    	 } 
    	Tarjan.clear(vec);int cop = Tl;
    	solve(mid+1,vr,Tl + l , r);
    	s.Del(lim);
    	solve(vl,mid,l,l+cop-1);
    }
    
    int ans[p];
    bitset<p> bit;
    int *en ; 
    inline int True(int x)
    {
    	return lower_bound(b+1 ,en , x) - b;
    }
    
    signed  main()
    {
    	read(n);
    	read(m);
    	read(q);
    	for(int i=1;i<=n;i++) read(a[i]) , b[++bili] = a[i];
    	
    	for(int i=1;i<=m;i++)
    	{
    		read(e[i].u);
    		read(e[i].v);
    		e[i].tim = 0;
    		mapp[{e[i].u ,e[i].v}] = i;
    	}
    	
    	for(int i=1;i<=q;i++)
    	{
    		read(qa[i].opt);read(qa[i].a);read(qa[i].b);
    		if(qa[i].opt == 1) e[mapp[{qa[i].a,qa[i].b}]].tim = q - i +1;
    		if(qa[i].opt == 2) b[++bili] = (a[qa[i].a] += qa[i].b);
    		if(qa[i].opt == 3) bit[i] = 1; 
    	}
    	s.Init(); solve(0 , q+1 , 1 , m);
    	sort(b+1,b+1+bili);
    	en = unique(b+1,b+1+bili);
    	int End = en - b - 1;
    	for(int i=1;i<=m;i++) c[i] = (node){1 , e[i].u , e[i].v , e[i].tim};
    	int Ti = m;
    	for(int i=1;i<=q;i++)
    	{
    		if(qa[i].opt!= 1) c[++Ti] = (node){qa[i].opt , qa[i].a , qa[i].b , q - i + 1};
    	} 
    	sort(c+1,c+1+Ti , [&](node A,node B){return A.tim < B.tim;});
    	
    	s1.Init();
    	for(int i=1;i<=n;i++){
    	
    	segT.update(segT.rot[i]=segT.New(1,End), True(a[i]) , 1);
    	} 
    	for(int i=1;i<=Ti;i++)
    	{
    		if(c[i].opt == 1) s1.Merge(s1.f(c[i].a) ,s1.f( c[i].b));
    		if(c[i].opt == 2)
    		{
    			int ftop = s1.f(c[i].a);
    			segT.update(segT.rot[ftop],True(a[c[i].a]) , -1);
    			a[c[i].a] -= c[i].b;
    			segT.update(segT.rot[ftop] , True(a[c[i].a]) , 1);
    		}
    		if(c[i].opt == 3)
    		{
    			int ftop = s1.f(c[i].a);
    			ans[q - c[i].tim + 1]  = segT.rot[ftop]->query(c[i].b);
    		}
    	}
    	
    	for(int i=1;i<= q;i++) if(bit[i]) printf("%lld
    ",ans[i]);
    	
    	return 0;
     }
    
    

    在役一年我就没写过封装的这么严重的题 , 代码难度真是能和维护数列平分秋风

    这个可以说是整体二分里面的天花板之一了

  • 相关阅读:
    携程呼叫中心异地双活——座席服务的高可用
    从5台服务器到两地三中心:魅族系统运维架构演进之路(含PPT)
    从“两地三中心”到“分布式多活”
    “两地三中心”容灾备份设计与实现_数据备份_数据恢复-阿里云
    膏方_百度百科
    矿泉水瓶加湿器 办公室空气加湿器迷你便携水瓶座 小型USB迷你家用静音 白色【图片 价格 品牌 报价】-京东
    【资料下载】ANTLR的最全的官方文档:The Definitive ANTLR Reference:v2,v3,v4版本都有下载 | 在路上
    “百万年薪40多万个税”高不高?你怎么看?_财经_腾讯网
    浙江四大滑雪场攻略及2015滑雪门票价格
    druid parser
  • 原文地址:https://www.cnblogs.com/-Iris-/p/15350322.html
Copyright © 2020-2023  润新知