讲题前先讲故事
miaom:你快来做这道题啊啊==我已经A掉了我教你 啊
YYMHL:吼啊
10 min later
miaom:你听懂了嘛?
YYMHL:不对啊
10 min later
YYMHL:我把你hack掉了啊
miaom:!!!那 你帮我改一下就当你自己做的好了
以下内容转自http://blog.youkuaiyun.com/Miao_zc/article/details/73656324
给每个数一个随机权值,如果两个序列的数的随机权值异或和相等可以认为这两个序列排序后相同。考虑主席树,对于两个区间l~r的数,二分一个将那对不同的数分开的数值,然后用区间最大(小)查询就能得到那两个不同的数,再判断一下即可。
复杂度由于在线段树上二分,复杂度O(nlogn)。
至于那个随机为什么对,只要考虑如果两个序列相等,异或和必定相等,否则最后的异或和是随机的,有2^-64相同,(1-2^-64)^(nlogn)的概率正确。//大概算出来是这个东西:
YYMHL:你这样异或分不清[1,1,1,2]和[1,2,2,2]啊,您会输出Y啊
miaom:mmp
#include<bits/stdc++.h>
#define ll long long
#define N 100005
#define M 100000
#define mod 2333333333333341
using namespace std;
int T,n,q,a[N],Rt[N];
int ls[2000005],rs[2000005],cnt,sz[2000005];
ll v[2000005],b[N];
ll rd()
{
return ((ll)rand()<<31LL)|rand();
}
void add(int p,int &q,int l,int r,int x)
{
q=++cnt;
v[q]=(v[p]+b[x])%mod;
sz[q]=sz[p]+1;
ls[q]=rs[q]=0;
if (l==r)return;
int mid=l+r>>1;
if (x<=mid) rs[q]=rs[p],add(ls[p],ls[q],l,mid,x);
else ls[q]=ls[p],add(rs[p],rs[q],mid+1,r,x);
}
int qMx(int x,int y,int l,int r)
{
if (l==r) return l;
int mid=l+r>>1;
if (sz[rs[x]]!=sz[rs[y]]) return qMx(rs[x],rs[y],mid+1,r);
return qMx(ls[x],ls[y],l,mid);
}
int qMn(int x,int y,int l,int r)
{
if (l==r) return l;
int mid=l+r>>1;
if (sz[ls[x]]!=sz[ls[y]]) return qMn(ls[x],ls[y],l,mid);
return qMn(rs[x],rs[y],mid+1,r);
}
bool check(int l1,int r1,int l2,int r2)
{
int l=1,r=M,mid;
l1=Rt[l1-1];r1=Rt[r1];
l2=Rt[l2-1];r2=Rt[r2];
if ((v[r1]-v[l1]+mod)%mod==(v[r2]-v[l2]+mod)%mod&&sz[r1]-sz[l1]==sz[r2]-sz[l2]) return 1;
while(l<r)
{
mid=l+r>>1;
if ((v[ls[r1]]-v[ls[l1]]+mod)%mod==(v[ls[r2]]-v[ls[l2]]+mod)%mod&&sz[ls[r1]]-sz[ls[l1]]==sz[ls[r2]]-sz[ls[l2]])
r1=rs[r1],l1=rs[l1],r2=rs[r2],l2=rs[l2],l=mid+1;
else if ((v[rs[r1]]-v[rs[l1]]+mod)%mod==(v[rs[r2]]-v[rs[l2]]+mod)%mod&&sz[rs[r1]]-sz[rs[l1]]==sz[rs[r2]]-sz[rs[l2]])
r1=ls[r1],l1=ls[l1],r2=ls[r2],l2=ls[l2],r=mid;
else
{
if ((sz[ls[r1]]-sz[ls[l1]])-(sz[ls[r2]]-sz[ls[l2]])==-1)
swap(l1,l2),swap(r1,r2);
if ((sz[ls[r1]]-sz[ls[l1]])-(sz[ls[r2]]-sz[ls[l2]])==1)
if ((v[r1]-v[l1]-b[qMx(ls[l1],ls[r1],l,mid)]+mod*2)%mod==(v[r2]-v[l2]-b[qMn(rs[l2],rs[r2],mid+1,r)]+mod*2)%mod)
return 1;
return 0;
}
}
return 1;
}
void work()
{
cnt=0;
scanf("%d%d",&n,&q);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
add(Rt[i-1],Rt[i],1,M,a[i]);
}
for (int i=1;i<=q;i++)
{
int l1,l2,r1,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
puts(check(l1,r1,l2,r2)?"YES":"NO");
}
}
int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
srand(time(0));
for (int i=1;i<=M;i++)
b[i]=(rd()%mod+mod)%mod;
sort(b+1,b+M+1);
for (int i=1;i<=M;i++)
b[i]=(b[i]+i)%mod;
random_shuffle(b+1,b+M+1);
scanf("%d",&T);
while(T--) work();
//system("pause");
}
另外一个故事:
YYMHL:为毛我A不掉啊
miaom:是不是随机种子的锅啊
YYMHL:这都可以
YYMHL:***Linux里面rand()可以到int啊QAQ你的种子会炸longlong的啊
miaom:可我过了啊
YYMHL:异或管你符号位啊
YYMHL:要是就这么A了就把你A了吧
wlc1121&wzf2000&caili413:吼啊吼啊
YYMHL:过了
miaom:-------