hdu 5172(线段树||HASH)

GTY‘s gay friends

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1379    Accepted Submission(s): 355

Problem Description

GTY has n
gay friends. To manage them conveniently, every morning he ordered all
his gay friends to stand in a line. Every gay friend has a
characteristic value ai
, to express how manly or how girlish he is. You, as GTY‘s assistant,
have to answer GTY‘s queries. In each of GTY‘s queries, GTY will give
you a range [l,r] . Because of GTY‘s strange hobbies, he wants there is a permutation [1..r−l+1] in [l,r]. You need to let him know if there is such a permutation or not.

Input

Multi test cases (about 3) . The first line contains two integers n and m ( 1≤n,m≤1000000
), indicating the number of GTY‘s gay friends and the number of GTY‘s
queries. the second line contains n numbers seperated by spaces. The ith number ai ( 1≤ai≤n ) indicates GTY‘s ith
gay friend‘s characteristic value. The next m lines describe GTY‘s
queries. In each line there are two numbers l and r seperated by spaces (
1≤l≤r≤n ), indicating the query range.

Output

For each query, if there is a permutation [1..r−l+1] in [l,r], print ‘YES‘, else print ‘NO‘.

Sample Input

8 5
2 1 3 4 5 2 3 1
1 3
1 1
2 2
4 8
1 5
3 2
1 1 1
1 1
1 2

Sample Output

YES NO YES YES YES YES NO

题意:

n个数m个询问,询问(l,r)中的数是否为1 ~ r-l+1的一个排列。

分析:

若(l,r)中的数为1 ~ r-l+1中的一个排列,则必须满足:

1、(l,r)中的数之和为len*(len+1)/2,其中len = r-l+1。

2、区间内的数字各不相同,即用线段树维护位置i上的数上次出现的位置的最大值。

只要区间内所有的数上次出现的位置last[i] < l,则区间内的数各不相同。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long LL;
const int N = 1000005;
int pre[N],now[N];
LL sum[N];
struct Tree{
    int MAX_ID;
}tree[N<<2];
int MAX_ID;
void PushUp(int idx){
    tree[idx].MAX_ID = max(tree[idx<<1].MAX_ID,tree[idx<<1|1].MAX_ID);
}
void build(int l,int r,int idx){
    if(l==r){
        tree[idx].MAX_ID = pre[l];
        return;
    }
    int mid = (l+r)>>1;
    build(l,mid,idx<<1);
    build(mid+1,r,idx<<1|1);
    PushUp(idx);
}
void query(int l,int r,int L,int R,int idx){
    if(l >= L&& r <= R){
        MAX_ID = max(MAX_ID,tree[idx].MAX_ID);
        return;
    }
    int mid = (l+r)>>1;
    if(mid>=L) query(l,mid,L,R,idx<<1);
    if(mid<R)  query(mid+1,r,L,R,idx<<1|1);
}
int main()
{
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF){
        memset(now,0,sizeof(now));
        sum[0] = 0;
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            sum[i] = sum[i-1]+x;
            pre[i] = now[x];
            now[x] = i;
        }
        build(1,n,1);
        while(k--){
            int l,r;
            scanf("%d%d",&l,&r);
            LL len = r-l+1;
            LL S = (len+1)*(len)/2;
            if(sum[r]-sum[l-1]!=S){
                printf("NO\n");
                continue;
            }
            MAX_ID = -1;
            query(1,n,l,r,1);
            if(MAX_ID<l) printf("YES\n");
            else printf("NO\n");
        }
    }
    return 0;
}

不过我们还有更简单的hash做法,对于[1..n][1..n][1..n]中的每一个数随机一个64位无符号整型作为它的hash值,一个集合的hash值为元素的异或和,预处理[1..n]的排列的hash和原序列的前缀hash异或和,就可以做到线性预处理,O(1)O(1)O(1)回答询问.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<ctime>
#define eps (1e-8)

using namespace std;

typedef long long ll;
unsigned long long ra[1000005],a[1000005],ha[1000005];
int n,m,t,p;

//int main(int argc,char const *argv[])
int main()
{
    srand(time(NULL));
    a[0] = ha[0] = 0;
    for(int i=1; i<=1000000; i++)
    {
        ra[i] = rand()*rand();
        ha[i] = ha[i-1]^ra[i];
    }
    for(int i=1; i<=20; i++)
    {
        printf("%lld\n",ra[i]);
    }
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&t);
            a[i] = ra[t];
            a[i]^=a[i-1];
        }
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&t,&p);
            puts((ha[p-t+1]==(a[p]^a[t-1])?"YES":"NO"));
        }
    }
    return 0;
}
时间: 2024-08-15 06:45:07

hdu 5172(线段树||HASH)的相关文章

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对 参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍 #include <cstdio> #include <cstring> #include <a

HDU 4902 线段树||暴力

给定一个序列,两种操作 1:把一段变成x. 2:把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 线段树解法:用lazy标记下即可,优化方法还是很巧妙的, Accepted 4902 515MS 3308K 1941 B C++ #include "stdio.h" #include "string.h" struct node { int l,r,x;// 在叶子节点代表值,树节点代表成端更新的lazy操作. }data[400010]

HDU 4302 线段树单点更新,维护区间最大最小值

http://acm.hdu.edu.cn/showproblem.php?pid=4302 Problem Description Holedox is a small animal which can be considered as one point. It lives in a straight pipe whose length is L. Holedox can only move along the pipe. Cakes may appear anywhere in the p

HDU 3397 线段树 双懒惰标记

这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了 自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了 跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全部置为0或者1,没有置位的时候为-1 还有个rev标记,代表翻转操作,0代表当前不翻,1代表当前翻 要注意一下优先级,发现有不同的弄法,我是这个弄得,有set操作的时候,set标记设值,并把当前节点的rev标记设为0,因为不管要不要rev,当前set操作肯定直接覆盖了 rev操作不改变set操作,在

hdu 2795 线段树--点更新

http://acm.hdu.edu.cn/showproblem.php?pid=2795 多校的第一场和第三场都出现了线段树,比赛期间没做,,这两天先做几道热身下,然后31号之前把那两道多校的线段树都搞了,这是一道热身题 关键是建模: 首先一定看清楚题目构造的场景,看有什么特点--------会发现,如果尽量往左上放置的话,那么由于 the i-th announcement is a rectangle of size 1 * wi.,完全可以对h建立线段树,表示一行,结点里的l,r就表示

HDU 1698 线段树(区间染色)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16255    Accepted Submission(s): 8089 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing f

HDU 3642 线段树+离散化+扫描线

题意:给你N个长方体的左下角和右上角坐标,问你空间中有多少体积是被大于两个不同的立方体覆盖的.x,y~10^6 z~500 考虑到给的z比较小,所以可以直接枚举z,然后跑二维的扫描线就好. 关于处理被不同的线段覆盖三次的问题,可以维护四个信息,cnt,once,twice,more,然后相互推出结果就好. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #