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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章