CCPC2023深圳 K-四国军棋(线段树维护单调栈哈希值)

传送门

解题思路

对于每个人的棋子,总是最高的那个棋子发挥决定性作用,被消耗后,再看剩下的最高的棋子。这就相当于单调不递增栈的维护过程。

最后就要比较两个人的单调不递增栈是否完全相同。

和经典的楼房重建相似,但是这个题不止需要维护单调栈的长度,还要维护哈希值。

我是分开写的,但是实际上可以直接用pair表示哈希值和长度,写起来条理一些。

顺便我把序列倒过来了(为了和楼房重建重合度大一些)

AC代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!(c>='0'&&c<='9')) {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=2e5+5;
const int mod=1e9+7;
int d[2][maxn*4],len[2][maxn*4],n,m,a[2][maxn];
long long Hash[2][maxn*4],mi[maxn];
int getans(int op,int id,int l,int r,int v){
	if(l==r) return d[op][id]>=v;
	if(d[op][id]<v) return 0;
	int mid=(l+r)/2;
	if(d[op][id*2]>=v) return getans(op,id*2,l,mid,v)+len[op][id]-len[op][id*2];
	return getans(op,id*2+1,mid+1,r,v);
}
long long gethash(int op,int id,int l,int r,int v){
	if(l==r) return d[op][id]>=v?Hash[op][id]:0;
	if(d[op][id]<v) return 0;
	int mid=(l+r)/2;
	if(d[op][id*2]>=v) return (gethash(op,id*2,l,mid,v)*mi[len[op][id]-len[op][id*2]]+(Hash[op][id]-Hash[op][id*2]*mi[len[op][id]-len[op][id*2]])%mod+mod)%mod;
	return gethash(op,id*2+1,mid+1,r,v);
}
void pushup(int op,int id,int l,int r){
	int mid=(l+r)/2;
	d[op][id]=max(d[op][id*2],d[op][id*2+1]);
	int x=getans(op,id*2+1,mid+1,r,d[op][id*2]);
	long long y=gethash(op,id*2+1,mid+1,r,d[op][id*2]);
	len[op][id]=len[op][id*2]+x;
	Hash[op][id]=(Hash[op][id*2]*mi[x]+y)%mod;
	return;
}
void add(int op,int id,int l,int r,int x,int v){
	if(l==r){
		d[op][id]=v;
		len[op][id]=1;
		Hash[op][id]=v%mod;
		return;
	}
	int mid=(l+r)/2;
	if(x<=mid) add(op,id*2,l,mid,x,v);
	else add(op,id*2+1,mid+1,r,x,v);
	pushup(op,id,l,r);
}
int main()
{
	mi[0]=1;
	for(int i=1;i<=200000;i++) mi[i]=mi[i-1]*998244353%mod;
	n=read();
	for(int i=n;i>=1;i--){
		a[0][i]=read();
		add(0,1,1,n,i,a[0][i]);
	}
	m=read();
	for(int i=m;i>=1;i--){
		a[1][i]=read();
		add(1,1,1,m,i,a[1][i]);
	}
	int T=read();
	while(T--){
		int op=read(),x=read(),y=read();
		if(op==1) add(0,1,1,n,n-x+1,y),a[0][n-x+1]=y;
		else add(1,1,1,m,m-x+1,y),a[1][m-x+1]=y;
		if(Hash[0][1]==Hash[1][1]) puts("YES");
		else puts("NO");
	}
    return 0;
}
posted @ 2024-02-27 20:57  尹昱钦  阅读(64)  评论(0编辑  收藏  举报