• 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;
    }
    

    总结

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

  • 相关阅读:
    Macos中Office的选择
    基于上一篇的滑动列表,动态添加/删除功能
    GitLab 服务搭建及常用命令
    java多线程中的异常处理
    java实现xml互转json
    nginx集群搭建方案(教你如何搭建nginx集群)
    cmd窗口改字符集编码
    ThreadLocal详解
    查看Linux系统版本信息的几种方法
    Windows命令之tasklist命令
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14932410.html
Copyright © 2020-2023  润新知