zoukankan      html  css  js  c++  java
  • CF526F Pudding Monsters

    题目

    分析

    析合树题。

    首先这样“每行每列恰好一个棋子”的条件是很明显的说这是一个排列。

    然后(k imes k)的矩阵这个条件再分析一下就容易得出这是指我们需要找出一个连续区间。

    那么把矩阵转化成数组,然后就是析合树模板题了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define PII pair<int,int>
    #define mp make_pair
    const int N=6e5+5;
    int n,m,a[N];
    namespace RMQ1{
    	int Max[N][21],lg[N];
    	inline void Init(int n){
    		for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
    		for(int i=1;i<=n;i++) Max[i][0]=a[i];
    		for(int i=1;i<=20;i++) for(int j=1;j+(1<<i)-1<=n;j++) Max[j][i]=max(Max[j][i-1],Max[j+(1<<(i-1))][i-1]);
    		return ;
    	}
    	inline int Query(int l,int r){
    		int tmp=lg[r-l+1];
    		return max(Max[l][tmp],Max[r-(1<<tmp)+1][tmp]);
    	}
    }
    namespace RMQ2{
    	int Min[N][21],lg[N];
    	inline void Init(int n){
    		for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
    		for(int i=1;i<=n;i++) Min[i][0]=a[i];
    		for(int i=1;i<=20;i++) for(int j=1;j+(1<<i)-1<=n;j++) Min[j][i]=min(Min[j][i-1],Min[j+(1<<(i-1))][i-1]);
    		return ;
    	}
    	inline int Query(int l,int r){
    		int tmp=lg[r-l+1];
    		return min(Min[l][tmp],Min[r-(1<<tmp)+1][tmp]);
    	}
    }
    int head[N],to[N<<1],nex[N<<1],idx;
    void add(int u,int v){
    	nex[++idx]=head[u];
    	to[idx]=v;
    	head[u]=idx;
    	return ;
    }
    int dep[N],fa[N][21],typ[N];
    long long Ans;
    void dfs(int x,int f){
    	dep[x]=dep[f]+1,fa[x][0]=f;long long tmp=0;
    	for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(y==f) continue;
    		dfs(y,x);tmp++;
    	}
    	if(typ[x]) Ans+=tmp*(tmp-1)/2;
    	else Ans++;
    	return ;
    }
    inline int QueryKth(int x,int k){
    	for(int i=0;i<=20;i++) if(k&(1<<i)) x=fa[x][i];
    	return x;
    }
    inline int QueryLca(int x,int y){
    	if(dep[x]<dep[y]) swap(x,y);
    	x=QueryKth(x,dep[x]-dep[y]);
    	if(x==y) return x;
    	for(int i=20;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    	return fa[x][0];
    }
    inline bool Check(int l,int r){return RMQ1::Query(l,r)-RMQ2::Query(l,r)==r-l;}
    int Min[N<<2],ad[N<<2];
    inline void Pushup(int x){
    	Min[x]=min(Min[x<<1],Min[x<<1|1]);
    	return ;
    }
    inline void PushDown(int x){
    	if(ad[x]){
    		ad[x<<1]+=ad[x],ad[x<<1|1]+=ad[x],Min[x<<1]+=ad[x],Min[x<<1|1]+=ad[x];
    		ad[x]=0;
    		return ;
    	}
    }
    void Modify(int x,int l,int r,int ql,int qr,int v){
    	if(ql<=l&&r<=qr) return Min[x]+=v,ad[x]+=v,void();
    	int mid=l+r>>1;PushDown(x);
    	if(ql<=mid) Modify(x<<1,l,mid,ql,qr,v);
    	if(qr>mid) Modify(x<<1|1,mid+1,r,ql,qr,v);
    	Pushup(x);
    	return ;
    }
    int Query(int x,int l,int r){
    	if(l==r) return l;
    	int mid=l+r>>1;PushDown(x);
    	if(!Min[x<<1]) return Query(x<<1,l,mid);
    	return Query(x<<1|1,mid+1,r);
    }
    int sta[N],top,sta1[N],top1,sta2[N],top2,id[N],cnt,L[N],R[N],lc[N],rt;
    void Build(){
    	for(int i=1;i<=n;i++){
    		while(top1&&a[i]<=a[sta1[top1]]) Modify(1,1,n,sta1[top1-1]+1,sta1[top1],a[sta1[top1]]),top1--;
    		while(top2&&a[i]>=a[sta2[top2]]) Modify(1,1,n,sta2[top2-1]+1,sta2[top2],-a[sta2[top2]]),top2--;
    		Modify(1,1,n,sta1[top1]+1,i,-a[i]),sta1[++top1]=i;
    		Modify(1,1,n,sta2[top2]+1,i,a[i]),sta2[++top2]=i;
    		id[i]=++cnt,L[cnt]=R[cnt]=i;
    		int tmp=Query(1,1,n),now=cnt;
    		while(top&&L[sta[top]]>=tmp){
    			if(typ[sta[top]]&&Check(lc[sta[top]],i)) R[sta[top]]=i,lc[sta[top]]=L[now],add(sta[top],now),now=sta[top--];
    			else if(Check(L[sta[top]],i)) typ[++cnt]=1,R[cnt]=i,L[cnt]=L[sta[top]],lc[cnt]=L[now],add(cnt,now),add(cnt,sta[top--]),now=cnt;
    			else{
    				add(++cnt,now);
    				do{add(cnt,sta[top--]);}while(top&&!Check(L[sta[top]],i));
    				R[cnt]=i,L[cnt]=L[sta[top]],add(cnt,sta[top--]),now=cnt;
    			}
    		}
    		Modify(1,1,n,1,i,-1);
    		sta[++top]=now;
    	}
    	rt=sta[1];
    }
    signed main(){
    	read(n);
    	for(int i=1;i<=n;i++){
    		int x,y;
    		read(x),read(y);
    		a[x]=y;
    	}
    	RMQ1::Init(n),RMQ2::Init(n);
    	Build();
    	dfs(rt,0);
    	write(Ans);
    	return 0;
    }
    

    总结

    需要注意的是:“每行每列恰好一个棋子”的条件是很明显的说这是一个排列这一个条件需要记住,类似的是八皇后和放车这样的东西。

  • 相关阅读:
    Java实现 LeetCode 56 合并区间
    JQuery实现对html结点的操作(创建,添加,删除)
    JQuery实现对html结点的操作(创建,添加,删除)
    JQuery实现对html结点的操作(创建,添加,删除)
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 54 螺旋矩阵
    Java实现 LeetCode 54 螺旋矩阵
    Java实现 LeetCode 54 螺旋矩阵
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14932410.html
Copyright © 2011-2022 走看看