zoukankan      html  css  js  c++  java
  • CF1109F Sasha and Algorithm of Silence's Sounds

    XXV.Sasha and Algorithm of Silence's Sounds

    假设我们把区间\([l,r]\)里的格子连出来,然后发现出现一个环,则我们可以肯定地说,所有具有\([l,r]\)作为子区间的区间,都是不合法的。

    于是我们对于每个位置\(l\),都可以找出其最右边的不成环的位置\(r\)。使用two-pointers思想,用LCT维护当前建出的图,即可做到\(O(n\log n)\)求解极大区间。

    下面我们只需要找出\([l,r]\)中有多少个\(k\)满足\([l,k]\)是树即可。显然因为已经保证无环了,所以我们只需要保证\((\text{点数}-\text{边数})=1\)即可。使用线段树维护即可把此部分也优化至\(O(n\log n)\)

    则总复杂度\(O(n\log n)\)

    (似乎因为CF不太支持 #define pushup (something)用在线段树里,我连着MLE了好几天才发现是这个缘故,以后还是老老实实写函数式pushup罢)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,m,lim,a[1010][1010],dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
    pair<int,int>p[1000100];
    ll res;
    namespace LCT{
    	#define lson t[x].ch[0]
    	#define rson t[x].ch[1]
    	struct Link_Cut_Tree{
    		int fa,ch[2];
    		bool rev;
    	}t[200100];
    	inline int identify(int x){
    		if(x==t[t[x].fa].ch[0])return 0;
    		if(x==t[t[x].fa].ch[1])return 1;
    		return -1;
    	}
    	inline void REV(int x){t[x].rev^=1,swap(lson,rson);}
    	inline void pushdown(int x){
    		if(!t[x].rev)return;
    		if(lson)REV(lson);
    		if(rson)REV(rson);
    		t[x].rev=0;
    	}
    	inline void rotate(int x){
    		register int y=t[x].fa,z=t[y].fa,dirx=identify(x),diry=identify(y),b=t[x].ch[!dirx];
    		if(diry!=-1)t[z].ch[diry]=x;t[x].fa=z;
    		if(b)t[b].fa=y;t[y].ch[dirx]=b;
    		t[y].fa=x,t[x].ch[!dirx]=y;
    	}
    	inline void pushall(int x){if(identify(x)!=-1)pushall(t[x].fa);pushdown(x);}
    	inline void splay(int x){for(pushall(x);identify(x)!=-1;rotate(x))if(identify(t[x].fa)!=-1)rotate(identify(x)==identify(t[x].fa)?t[x].fa:x);}
    	inline void access(int x){for(register int y=0;x;x=t[y=x].fa)splay(x),rson=y;}
    	inline void makeroot(int x){access(x),splay(x),REV(x);}
    	inline int findroot(int x){access(x),splay(x),pushdown(x);while(lson)x=lson,pushdown(x);splay(x);return x;}
    	inline void split(int x,int y){makeroot(x),access(y),splay(y);}
    	inline bool link(int x,int y){if(findroot(x)==findroot(y))return false;makeroot(x),t[x].fa=y;return true;}
    	inline void cut(int x,int y){split(x,y),t[y].ch[0]=t[x].fa=0;}
    	#undef lson
    	#undef rson
    } 
    namespace SG{
    	#define lson x<<1
    	#define rson x<<1|1
    	#define mid ((l+r)>>1)
    	struct SegTree{
    		int mn,num,tag;
    	}seg[800100];
    	void ADD(int x,int y){seg[x].mn+=y,seg[x].tag+=y;}
    	void pushdown(int x){ADD(lson,seg[x].tag),ADD(rson,seg[x].tag),seg[x].tag=0;}
    	void pushup(int x){
    		seg[x].mn=min(seg[lson].mn,seg[rson].mn),seg[x].num=0;
    		if(seg[x].mn==seg[lson].mn)seg[x].num+=seg[lson].num;
    		if(seg[x].mn==seg[rson].mn)seg[x].num+=seg[rson].num;
    	}
    	void build(int x,int l,int r){
    		if(l==r){seg[x].mn=0,seg[x].num=1;return;}
    		build(lson,l,mid),build(rson,mid+1,r),pushup(x);
    	}
    	void modify(int x,int l,int r,int L,int R,int val){
    		if(l>R||r<L)return;
    		if(L<=l&&r<=R){ADD(x,val);return;}
    		pushdown(x),modify(lson,l,mid,L,R,val),modify(rson,mid+1,r,L,R,val),pushup(x); 
    	}
    	int query(int x,int l,int r,int L,int R){
    		if(l>R||r<L)return 0;
    		if(L<=l&&r<=R)return seg[x].mn==1?seg[x].num:0;
    		pushdown(x);
    		return query(lson,l,mid,L,R)+query(rson,mid+1,r,L,R);
    	}
    	#undef lson
    	#undef rson
    	#undef mid
    }
    #define P a[x+dx[i]][y+dy[i]]
    int main(){
    	scanf("%d%d",&n,&m),lim=n*m;
    	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]),p[a[i][j]]=make_pair(i,j);
    	SG::build(1,1,lim);
    	for(int l=1,r=1;l<=lim;l++){
    		while(r<=lim){
    			int x=p[r].first,y=p[r].second;
    			int cnt=0;
    			for(int i=0;i<4;i++){
    				if(!(P>=l&&P<r))continue;
    				cnt++;
    				if(LCT::link(r,P))continue;
    				for(i--;i>=0;i--)if(P>=l&&P<r)LCT::cut(r,P);
    				cnt=-1;
    				break;
    			}
    			if(cnt==-1)break;
    			SG::modify(1,1,lim,r,lim,-cnt);
    			SG::modify(1,1,lim,r,r,r-l+1);
    			r++;
    		}
    		res+=SG::query(1,1,lim,l,r-1);
    		SG::modify(1,1,lim,l,r-1,-1);
    		int x=p[l].first,y=p[l].second;
    		for(int i=0;i<4;i++)if(P>=l&&P<r)LCT::cut(l,P),SG::modify(1,1,lim,P,lim,1);
    	}
    	printf("%lld\n",res);
    	return 0;
    }
    

  • 相关阅读:
    java中栈内存和堆内存的简单理解
    java中构造函数与一般函数的区别

    另一部漫画
    海边的卡夫卡
    11-12
    这篇大概值一百万吧
    我的千岁寒
    11-9
    嗯……………股票已经涨的我不想上班了
  • 原文地址:https://www.cnblogs.com/Troverld/p/14602235.html
Copyright © 2011-2022 走看看