zoukankan      html  css  js  c++  java
  • 题解-APIO2019桥梁

    problem

    (mathrm {loj-3145})

    题意概要:给定一张 (n)(m) 边的无向图,边有边权,共 (q) 次操作,每次会将第 (x) 条边的权值改为 (y),或询问从 (x) 开始只走大于等于 (y) 的边能到达多少点。

    (nleq 5 imes 10^4, m,qleq 10^5)

    Solution

    这道题和 (HNOI2016) 最小公因数 长得很像,想到分块就会了。由于这题有修改,对询问的权值分块不好做,就只能对操作分块了。

    设操作块大小为 (T),则共 (lceilfrac qT ceil) 个操作快。

    对于每一个操作块,按照询问的权值大小顺序询问(否则就需要上可持久化并查集)。需要考虑两者的贡献:在块内被修改了的边、在块内未被修改的边。后者可以依照询问的权值大小依次添加,而由于目前将询问按权值大小排序,所以询问时间不一定递增,可以暴力处理块内修改,查看这条边是否有用。

    对于每一个询问,需要暴力扫描块内的修改,每次修改因为需要支持并查集撤销,复杂度 (O(Tlog n))。总共 (q) 个询问,共 (O(qTlog n))

    对于每一块而言,需要将所有边排序、块内询问排序,处理整块排序时会重构整个并查集,复杂度 (O(n+mlog m+Tlog T)),由于 (n,m,q) 同阶,所以简化为 (O(mlog m))。总共 (lceil frac qT ceil) 块,共 (O(frac qTcdot mlog m))

    考虑到 (n,m,q) 同阶,总复杂度为 (O(mTlog m+frac {m^2log m}T)=O(mlog m(T+frac mT))),取 (T=m^{frac 12}) 得复杂度最低为 (O(m^{frac 32}log m))。到这就能过了

    实际上没必要每一块内重新排序,可以将一开始排序后的序列拆出来,复杂度 (O(m)),重新计算复杂度得 (O(mTlog m+frac {m^2}T)),取 (T=sqrt {mlog m}) 可得 (O(m^{frac 32}sqrt {log m}))……但效率差别并不是很大。

    Code

    这里写的是前一个版本的。

    //loj-3145
    #include <bits/stdc++.h>
    using namespace std;
    
    template <typename _tp> inline void read(_tp&x){
    	char ch=getchar(),ob=0;x=0;
    	while(ch!='-'&&!isdigit(ch))ch=getchar();if(ch=='-')ob=1,ch=getchar();
    	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();if(ob)x=-x;
    }
    
    const int N = 101000;
    int n, m, Q;
    
    struct Edge {
    	int l, r, w, id;
    	inline void in() {read(l), read(r), read(w);}
    	friend inline bool operator < (const Edge&A, const Edge&B) {return A.w > B.w;}
    }e[N], ee[N];
    
    struct Qry {
    	int op, x, y, id;
    	inline void in() {read(op), read(x), read(y);}
    	friend inline bool operator < (const Qry&A, const Qry&B) {return A.y > B.y;}
    }q[N], md[N], qr[N];
    
    int d[N], sz[N];
    inline int f(int x) {while(d[x]) x = d[x]; return x;}
    
    struct RUB {int x, dx, y, sy;}Rub[N];
    int rub;
    
    inline void merge(int x, int y) {
    	x = f(x), y = f(y); if(x == y) return ;
    	if(sz[x] > sz[y]) swap(x, y);
    	Rub[++rub] = (RUB) {x, d[x], y, sz[y]};
    	d[x] = y, sz[y] += sz[x];
    }
    
    inline void cancel() {while(rub) d[Rub[rub].x] = Rub[rub].dx, sz[Rub[rub].y] = Rub[rub].sy, --rub;}
    
    int Ans[N], st[N], ew[N];
    bool ex[N];
    
    int main() {
    	read(n), read(m);
    	for(int i=1;i<=m;++i) e[i].in(), e[i].id = i;
    	int T = max(1.0, sqrt(m*log(m)/log(2)));
    	read(Q);
    	for(int l=1,r=T;l<=Q;l+=T) {
    		r = min(Q, l+T-1);
    		int t = r - l + 1, t0 = 0, t1 = 0;
    
    		for(int i=1;i<=m;++i) ex[i] = false;
    
    		for(int i=1;i<=t;++i) {
    			Ans[i] = 0, q[i].in(), q[i].id = i;
    			if(q[i].op == 1) md[++t0] = q[i], ex[q[i].x] = true;
    			else qr[++t1] = q[i];
    		}
    		sort(qr+1, qr+t1+1);
    		
    		for(int i=1;i<=n;++i) d[i] = 0, sz[i] = 1;
    
    		int em = 0, tp = 0;
    		for(int i=1;i<=m;++i)
    			if(!ex[i]) ee[++em] = e[i];
    			else st[++tp] = i;
    		sort(ee+1, ee+em+1);
    
    		int ie = 1;
    		for(int i=1;i<=t1;++i) {
    			while(ie <= em and ee[ie].w >= qr[i].y)
    				merge(ee[ie].l, ee[ie].r), ++ie;
    			
    			for(int j=1;j<=tp;++j) ew[st[j]] = e[st[j]].w;
    			for(int j=1;j<=t0 and md[j].id <= qr[i].id;++j)
    				ew[md[j].x] = md[j].y;
    			rub = 0;
    			for(int j=1;j<=tp;++j)
    				if(ew[st[j]] >= qr[i].y)
    					merge(e[st[j]].l, e[st[j]].r);
    			Ans[qr[i].id] = sz[f(qr[i].x)];
    			cancel();
    		}
    		for(int i=1;i<=t0;++i)
    			e[md[i].x].w = md[i].y;
    		for(int i=1;i<=t;++i)
    			if(Ans[i]) printf("%d
    ", Ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    (转)【web前端培训之前后端的配合(中)】继续昨日的故事
    ural(Timus) 1136. Parliament
    scau Josephus Problem
    ACMICPC Live Archive 6204 Poker End Games
    uva 10391 Compound Words
    ACMICPC Live Archive 3222 Joke with Turtles
    uva 10132 File Fragmentation
    uva 270 Lining Up
    【转】各种字符串哈希函数比较
    uva 10905 Children's Game
  • 原文地址:https://www.cnblogs.com/penth/p/11382677.html
Copyright © 2011-2022 走看看