zoukankan      html  css  js  c++  java
  • CF1270H. Number of Components

    题目大意

    ij之间有边当且仅当i<j且a[i]<a[j],动态修改a,求连通块个数

    题解

    线段树吼题

    转换一:把求连通块个数变成求分界线个数

    设a[0]=inf,a[n+1]=-inf

    分界线的定义:min(a[1...i])>max(a[i+1...n])

    转换二:设h[i][j]=[a[j]>a[i]],则点i的a[i]能把图分成两块当且仅当h[i]中前面一段是1,后面一段是0

    手玩一下即可,刚好可以按十字分成左上和右下

    于是变成维护有多少个i满足h[i]只有两段,等于维护h[a[i]]中 10子串 个数

    直接维护所有h[i],同时维护i是否存在,修改只与a[x-1]、a[x]、a[x+1]和y有关(影响是一段区间)

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define max(a,b) (a>b?a:b)
    #define min(a,b) (a<b?a:b)
    #define ll long long
    #define N 1000000
    //#define file
    using namespace std;
    
    int tr[4000001][2],Tr[4000001],a[500002],n,Q,i,j,k,l,x,y;
    
    void down(int t,int len)
    {
    	if (Tr[t])
    	{
    		if (len>1) Tr[t*2]+=Tr[t],Tr[t*2+1]+=Tr[t];
    		tr[t][0]+=Tr[t];
    		Tr[t]=0;
    	}
    }
    void up(int t)
    {
    	if (tr[t*2][0]<tr[t*2+1][0])
    	tr[t][0]=tr[t*2][0],tr[t][1]=tr[t*2][1];
    	else
    	if (tr[t*2][0]>tr[t*2+1][0])
    	tr[t][0]=tr[t*2+1][0],tr[t][1]=tr[t*2+1][1];
    	else
    	tr[t][0]=tr[t*2][0],tr[t][1]=tr[t*2][1]+tr[t*2+1][1];
    }
    
    void change(int t,int l,int r,int x,int y,int s)
    {
    	x=max(x,1);y=min(y,N);
    	if (x>y) return;
    	
    	int mid=(l+r)/2;
    	down(t,r-l+1);
    	if (x<=l && r<=y) {Tr[t]+=s;down(t,r-l+1);return;}
    	
    	down(t*2,mid-l+1);down(t*2+1,r-mid);
    	if (x<=mid) change(t*2,l,mid,x,y,s);
    	if (mid<y) change(t*2+1,mid+1,r,x,y,s);
    	
    	up(t);
    }
    void Change(int t,int l,int r,int x,int s)
    {
    	int mid=(l+r)/2;
    	down(t,r-l+1);
    	if (l==r) {tr[t][1]+=s;return;}
    	
    	down(t*2,mid-l+1);down(t*2+1,r-mid);
    	if (x<=mid) Change(t*2,l,mid,x,s);
    	else Change(t*2+1,mid+1,r,x,s);
    	
    	up(t);
    }
    
    int main()
    {
    	#ifdef file
    	freopen("CF1270H.in","r",stdin);
    	#endif
    	
    	scanf("%d%d",&n,&Q);
    	a[0]=1919810;a[n+1]=-1919810;
    	fo(i,1,n) scanf("%d",&a[i]),Change(1,1,N,a[i],1);
    	fo(i,0,n) if (a[i]>a[i+1]) change(1,1,N,a[i+1],a[i]-1,1);
    	
    	for (;Q;--Q)
    	{
    		scanf("%d%d",&x,&y);
    		Change(1,1,N,a[x],-1);
    		if (a[x-1]>a[x]) change(1,1,N,a[x],a[x-1]-1,-1);
    		if (a[x]>a[x+1]) change(1,1,N,a[x+1],a[x]-1,-1);
    		a[x]=y;
    		Change(1,1,N,a[x],1);
    		if (a[x-1]>a[x]) change(1,1,N,a[x],a[x-1]-1,1);
    		if (a[x]>a[x+1]) change(1,1,N,a[x+1],a[x]-1,1);
    		
    		printf("%d
    ",tr[1][1]);
    	}
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    
  • 相关阅读:
    多机部署之定时任务完整方案
    老项目多机部署初步解决方案
    java多线程与线程池
    HotSpot项目结构
    调试HotSpot源代码
    在Ubuntu 16.04上编译OpenJDK8的源代码
    研究Java语言的编译器和虚拟机可参阅的资料
    我的书籍《深入解析Java编译器:源码剖析与实例详解》就要出版了
    hotspot编译
    研究小技巧及专业术语
  • 原文地址:https://www.cnblogs.com/gmh77/p/12799338.html
Copyright © 2011-2022 走看看