zoukankan      html  css  js  c++  java
  • Codeforces 1270 H. Number of Components(找性质+线段树)

    https://codeforces.com/contest/1270/problem/H

    考虑一个联通块一定是一个连续段,可以反证,假设有两段,发现中间的数一定会和两段相连。

    那么其实就是要求分界点的个数。

    一个分界点可以定义为左边的数全部大于等于右边的数。

    那么枚举一个(vin a[i]),把(ge v)的数标记为1,(< v)的数标记为0.

    因为数互不相同,(v)能作为某个地方的分界点,相当于标记后的序列(11110000)
    也就是相邻的标记不同的个数=1,最左边看作一个1,最右边看作一个0.

    (f[v])的相邻的标记不同的个数。

    那么对于修改一个位置的值,可以对(f)区间修改。

    然后查询(sum_{i=1}^n [f[a[i]]=1]),线段树维护最小值及最小值个数即可。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 1e6 + 5;
    
    int n, q;
    int a[N], b[N][2];
    int d[N], d0;
    
    map<int, int> bd;
    
    #define i0 i + i
    #define i1 i + i + 1
    struct P {
    	int x, y;
    } t[N * 4];
    
    P operator + (P a, P b) {
    	if(a.x != b.x) return a.x < b.x ? a : b;
    	return (P) {a.x, a.y + b.y};
    }
    
    int lz[N * 4];
    int pl, pr, px;
    void jia(int i, int v) {
    	t[i].x += v, lz[i] += v;
    }
    void down(int i) {
    	if(lz[i]) {
    		jia(i0, lz[i]);
    		jia(i1, lz[i]);
    		lz[i] = 0;
    	}
    }
    void add(int i, int x, int y) {
    	if(y < pl || x > pr) return;
    	if(x >= pl && y <= pr) {
    		jia(i, px); return;
    	}
    	int m = x + y >> 1; down(i);
    	add(i0, x, m); add(i1, m + 1, y);
    	t[i] = t[i0] + t[i1];
    }
    void xiu(int i, int x, int y) {
    	if(y < pl || x > pr) return;
    	if(x == y) {
    		t[i].y += px; return;
    	}
    	int m = x + y >> 1; down(i);
    	xiu(i0, x, m); xiu(i1, m + 1, y);
    	t[i] = t[i0] + t[i1];
    }
    
    void Init() {
    	scanf("%d %d", &n, &q);
    	fo(i, 1, n) scanf("%d", &a[i]), d[++ d0] = a[i];
    	fo(i, 1, q) {
    		scanf("%d %d", &b[i][0], &b[i][1]);
    		d[++ d0] = b[i][1];
    	}
    	sort(d + 1, d + d0 + 1);
    	d0 = unique(d + 1, d + d0 + 1) - (d + 1);
    	fo(i, 1, d0) bd[d[i]] = i;
    }
    
    void gai(int x, int xs) {
    	if(x == 0) {
    		pl = a[x + 1], pr = d0, px = xs;
    		add(1, 1, d0);
    	} else
    	if(x == n) {
    		pl = 1, pr = a[x] - 1; px = xs;
    		add(1, 1, d0);
    	} else {
    		if(a[x] != a[x + 1]) {
    			pl = a[x], pr = a[x + 1];
    			if(pl > pr) swap(pl, pr);
    			pr --; px = xs;
    			add(1, 1, d0);
    		}
    	}
    }
    
    int cnt[N];
    
    void add_cnt(int x, int xs) {
    	if(xs == 1) {
    		if(++ cnt[x] == 1) {
    			pl = pr = x; px = 1;
    			xiu(1, 1, d0);
    		}
    	} else {
    		if(-- cnt[x] == 0) {
    			pl = pr = x; px = -1;
    			xiu(1, 1, d0);
    		}
    	}
    }
    
    void build() {
    	fo(i, 1, n) {
    		a[i] = bd[a[i]];
    		add_cnt(a[i], 1);
    	}
    	fo(i, 0, n) gai(i, 1);
    }
    
    void work() {
    	fo(i, 1, q) {
    		int x, y;
    		x = b[i][0], y = b[i][1];
    		y = bd[y];
    		
    		add_cnt(a[x], -1);
    		gai(x - 1, -1); gai(x, -1);
    		
    		a[x] = y;
    		add_cnt(a[x], 1);
    		gai(x - 1, 1); gai(x, 1);
    		
    		pp("%d
    ", t[1].x == 1 ? t[1].y : 0);
    	}
    }
    
    int main() {
    	Init();
    	build();
    	work();
    }
    
  • 相关阅读:
    fedora29 安装mongodb 4.0,6问题记录
    乱花渐入迷人眼------从解决jqueryEasyUI上传插件提交ajax请求谈网页调试
    thinkphp5权限仿制
    基于tornado python pandas和bootstrap上传组件的mongodb数据添加工具
    tornado下pandas ndarray乱试
    一个tornado框架下的文件上传案例
    一例tornado框架下利用python panda对数据进行crud操作
    PHP 基础语法实例及注意事项
    转:github使用教程(重装系统后遇到问题该文章帮我解决了)
    ubuntu同步系统时间命令
  • 原文地址:https://www.cnblogs.com/coldchair/p/12794384.html
Copyright © 2011-2022 走看看